Version in base suite: 21.0.8+9-1 Base version: openjdk-21_21.0.8+9-1 Target version: openjdk-21_21.0.9+10-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/o/openjdk-21/openjdk-21_21.0.8+9-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/o/openjdk-21/openjdk-21_21.0.9+10-1~deb13u1.dsc /srv/release.debian.org/tmp/emfaCnEiU2/openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/duke.gif |binary /srv/release.debian.org/tmp/emfaCnEiU2/openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/duke.gif |binary /srv/release.debian.org/tmp/emfaCnEiU2/openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/duke.gif |binary openjdk-21-21.0.9+10/.jcheck/conf | 2 openjdk-21-21.0.9+10/debian/changelog | 50 openjdk-21-21.0.9+10/debian/copyright | 2 openjdk-21-21.0.9+10/debian/copyright-generator/copyright-gen.py | 2 openjdk-21-21.0.9+10/debian/patches/default-jvm-cfg.diff | 4 openjdk-21-21.0.9+10/debian/patches/icedtea-override-redirect-compiz.diff | 2 openjdk-21-21.0.9+10/debian/patches/jdk-8307977-proposed.patch | 81 openjdk-21-21.0.9+10/debian/patches/jdk-8334502-proposed.patch | 2 openjdk-21-21.0.9+10/debian/patches/jdk-8359735.patch | 6 openjdk-21-21.0.9+10/debian/patches/jdk-8369450-proposed.patch | 18 openjdk-21-21.0.9+10/debian/patches/jdk-getAccessibleValue.diff | 30 openjdk-21-21.0.9+10/debian/patches/make-debug-print.diff | 2 openjdk-21-21.0.9+10/debian/patches/multiple-pkcs11-library-init.diff | 6 openjdk-21-21.0.9+10/debian/patches/series | 2 openjdk-21-21.0.9+10/debian/patches/zero-alpha-workaround.diff | 2 openjdk-21-21.0.9+10/debian/rules | 11 openjdk-21-21.0.9+10/debian/tests/control | 2 openjdk-21-21.0.9+10/debian/tests/control.in | 2 openjdk-21-21.0.9+10/debian/tests/dependencies.sh | 2 openjdk-21-21.0.9+10/debian/tests/hotspot-autopkgtest.in | 1 openjdk-21-21.0.9+10/debian/tests/hotspot-autopkgtest.sh | 1 openjdk-21-21.0.9+10/debian/tests/jdk-autopkgtest.in | 1 openjdk-21-21.0.9+10/debian/tests/jdk-autopkgtest.sh | 1 openjdk-21-21.0.9+10/debian/tests/problems.csv | 56 openjdk-21-21.0.9+10/debian/tests/skip-large-autopkgtest.txt | 7 openjdk-21-21.0.9+10/doc/building.html | 8 openjdk-21-21.0.9+10/doc/building.md | 6 openjdk-21-21.0.9+10/make/Global.gmk | 3 openjdk-21-21.0.9+10/make/Install.gmk | 43 openjdk-21-21.0.9+10/make/Main.gmk | 8 openjdk-21-21.0.9+10/make/RunTestsPrebuilt.gmk | 6 openjdk-21-21.0.9+10/make/autoconf/build-performance.m4 | 5 openjdk-21-21.0.9+10/make/autoconf/flags-cflags.m4 | 2 openjdk-21-21.0.9+10/make/autoconf/lib-tests.m4 | 2 openjdk-21-21.0.9+10/make/autoconf/spec.gmk.in | 51 openjdk-21-21.0.9+10/make/conf/github-actions.conf | 2 openjdk-21-21.0.9+10/make/conf/jib-profiles.js | 2 openjdk-21-21.0.9+10/make/conf/version-numbers.conf | 4 openjdk-21-21.0.9+10/make/data/hotspot-symbols/symbols-linux | 1 openjdk-21-21.0.9+10/make/modules/java.desktop/lib/Awt2dLibraries.gmk | 10 openjdk-21-21.0.9+10/make/modules/jdk.internal.le/Lib.gmk | 5 openjdk-21-21.0.9+10/make/test/BuildTestLib.gmk | 3 openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/assembler_aarch64.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp | 12 openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/frame_ppc.cpp | 13 openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.cpp | 12 openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp | 13 openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/methodHandles_ppc.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/assembler_riscv.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.cpp | 8 openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp | 8 openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/riscv.ad | 31 openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/templateTable_riscv.cpp | 36 openjdk-21-21.0.9+10/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/cpu/x86/macroAssembler_x86.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/os/aix/os_aix.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupSubsystem_linux.cpp | 373 ++- openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupSubsystem_linux.hpp | 291 +- openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupUtil_linux.cpp | 159 + openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupUtil_linux.hpp | 43 openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp | 294 +- openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp | 151 - openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp | 228 + openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp | 131 - openjdk-21-21.0.9+10/src/hotspot/os/linux/osContainer_linux.cpp | 49 openjdk-21-21.0.9+10/src/hotspot/os/linux/osContainer_linux.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/os/linux/os_linux.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/os/posix/signals_posix.cpp | 10 openjdk-21-21.0.9+10/src/hotspot/os_cpu/aix_ppc/javaThread_aix_ppc.cpp | 19 openjdk-21-21.0.9+10/src/hotspot/os_cpu/linux_ppc/javaThread_linux_ppc.cpp | 19 openjdk-21-21.0.9+10/src/hotspot/share/adlc/output_h.cpp | 3 openjdk-21-21.0.9+10/src/hotspot/share/c1/c1_Compilation.cpp | 8 openjdk-21-21.0.9+10/src/hotspot/share/cds/classListParser.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/share/cds/classListWriter.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/cds/filemap.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/ci/ciEnv.cpp | 9 openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoader.cpp | 48 openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoader.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoaderExt.cpp | 10 openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.cpp | 41 openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.hpp | 38 openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.inline.hpp | 4 openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClassesImpl.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/classfile/stackMapTable.cpp | 10 openjdk-21-21.0.9+10/src/hotspot/share/classfile/stackMapTable.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/classfile/verifier.cpp | 35 openjdk-21-21.0.9+10/src/hotspot/share/classfile/vmClassMacros.hpp | 1 openjdk-21-21.0.9+10/src/hotspot/share/classfile/vmSymbols.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/code/dependencyContext.cpp | 18 openjdk-21-21.0.9+10/src/hotspot/share/code/dependencyContext.hpp | 5 openjdk-21-21.0.9+10/src/hotspot/share/compiler/compilationLog.cpp | 6 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp | 6 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp | 50 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1Policy.cpp | 38 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1RemSet.cpp | 6 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp | 6 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/bufferNode.cpp | 8 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/bufferNode.hpp | 8 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/gcArguments.cpp | 8 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/locationPrinter.inline.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/ptrQueue.cpp | 9 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/ptrQueue.hpp | 8 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/satbMarkQueue.cpp | 14 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/satbMarkQueue.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/weakProcessorTimes.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/workerDataArray.cpp | 9 openjdk-21-21.0.9+10/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp | 98 openjdk-21-21.0.9+10/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp | 11 openjdk-21-21.0.9+10/src/hotspot/share/include/jvm.h | 3 openjdk-21-21.0.9+10/src/hotspot/share/interpreter/bytecodeStream.hpp | 19 openjdk-21-21.0.9+10/src/hotspot/share/jfr/support/jfrSymbolTable.cpp | 69 openjdk-21-21.0.9+10/src/hotspot/share/jfr/support/jfrSymbolTable.hpp | 7 openjdk-21-21.0.9+10/src/hotspot/share/oops/cpCache.hpp | 9 openjdk-21-21.0.9+10/src/hotspot/share/opto/convertnode.cpp | 5 openjdk-21-21.0.9+10/src/hotspot/share/opto/loopnode.cpp | 14 openjdk-21-21.0.9+10/src/hotspot/share/opto/loopopts.cpp | 9 openjdk-21-21.0.9+10/src/hotspot/share/opto/mulnode.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/share/opto/reg_split.cpp | 34 openjdk-21-21.0.9+10/src/hotspot/share/opto/subnode.cpp | 4 openjdk-21-21.0.9+10/src/hotspot/share/opto/type.cpp | 20 openjdk-21-21.0.9+10/src/hotspot/share/prims/jvm.cpp | 15 openjdk-21-21.0.9+10/src/hotspot/share/prims/methodHandles.cpp | 33 openjdk-21-21.0.9+10/src/hotspot/share/prims/whitebox.cpp | 34 openjdk-21-21.0.9+10/src/hotspot/share/prims/whitebox.hpp | 5 openjdk-21-21.0.9+10/src/hotspot/share/runtime/globals.hpp | 4 openjdk-21-21.0.9+10/src/hotspot/share/runtime/mutexLocker.cpp | 3 openjdk-21-21.0.9+10/src/hotspot/share/runtime/mutexLocker.hpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/runtime/os.cpp | 50 openjdk-21-21.0.9+10/src/hotspot/share/runtime/os.hpp | 5 openjdk-21-21.0.9+10/src/hotspot/share/runtime/threads.cpp | 23 openjdk-21-21.0.9+10/src/hotspot/share/sanitizers/ub.hpp | 9 openjdk-21-21.0.9+10/src/hotspot/share/services/memReporter.cpp | 5 openjdk-21-21.0.9+10/src/hotspot/share/utilities/globalDefinitions.hpp | 8 openjdk-21-21.0.9+10/src/hotspot/share/utilities/spinYield.cpp | 2 openjdk-21-21.0.9+10/src/hotspot/share/utilities/vmError.cpp | 8 openjdk-21-21.0.9+10/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java | 6 openjdk-21-21.0.9+10/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java | 5 openjdk-21-21.0.9+10/src/java.base/linux/native/libjava/CgroupMetrics.c | 6 openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/AbstractStringBuilder.java | 9 openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/Class.java | 36 openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/invoke/CallSite.java | 6 openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java | 25 openjdk-21-21.0.9+10/src/java.base/share/classes/java/math/BigInteger.java | 226 + openjdk-21-21.0.9+10/src/java.base/share/classes/java/text/MessageFormat.java | 2 openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/Currency.java | 22 openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/Formatter.java | 6 openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java | 2 openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java | 44 openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java | 44 openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/zip/GZIPInputStream.java | 24 openjdk-21-21.0.9+10/src/java.base/share/classes/jdk/internal/platform/Metrics.java | 17 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/launcher/LauncherHelper.java | 7 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java | 14 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/nio/cs/Unicode.java | 8 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/Alert.java | 10 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java | 40 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java | 124 - openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java | 49 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/ClientHello.java | 6 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java | 5 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java | 4 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java | 21 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java | 34 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLLogger.java | 8 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLScope.java | 55 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java | 104 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/ServerHello.java | 24 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java | 9 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java | 119 - openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java | 129 - openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/util/DerValue.java | 16 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java | 117 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java | 16 openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/x509/AVA.java | 48 openjdk-21-21.0.9+10/src/java.base/share/conf/security/java.security | 25 openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustcommercialca | 27 openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustnetworkingca | 27 openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustpremiumca | 38 openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustpremiumeccca | 20 openjdk-21-21.0.9+10/src/java.base/share/data/currency/CurrencyData.properties | 8 openjdk-21-21.0.9+10/src/java.base/share/data/lsrdata/language-subtag-registry.txt | 122 + openjdk-21-21.0.9+10/src/java.base/share/native/launcher/main.c | 22 openjdk-21-21.0.9+10/src/java.base/share/native/libjava/ub.h | 9 openjdk-21-21.0.9+10/src/java.base/share/native/libjli/java.c | 7 openjdk-21-21.0.9+10/src/java.base/share/native/libverify/check_code.c | 39 openjdk-21-21.0.9+10/src/java.base/unix/native/libjava/java_props_md.c | 2 openjdk-21-21.0.9+10/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java | 32 openjdk-21-21.0.9+10/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java | 8 openjdk-21-21.0.9+10/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m | 33 openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java | 14 openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java | 20 openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java | 123 + openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java | 13 openjdk-21-21.0.9+10/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java | 62 openjdk-21-21.0.9+10/src/java.desktop/share/classes/java/beans/Introspector.java | 10 openjdk-21-21.0.9+10/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java | 143 - openjdk-21-21.0.9+10/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java | 22 openjdk-21-21.0.9+10/src/java.desktop/share/classes/sun/font/FileFontStrike.java | 1 openjdk-21-21.0.9+10/src/java.desktop/share/legal/harfbuzz.md | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libfontmanager/freetypeScaler.c | 1 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh | 12 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh | 158 + openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh | 11 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh | 15 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh | 24 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh | 5 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh | 158 - openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh | 21 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh | 144 + openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh | 62 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh | 84 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh | 47 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc | 59 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh | 8 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc | 5 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh | 80 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh | 4 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-bit-vector.hh | 195 + openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh | 602 ++--- openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh | 843 +++---- openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh | 192 - openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc | 22 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc | 35 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc | 16 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.h | 61 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh | 5 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-cache.hh | 37 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh | 66 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-common.cc | 63 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-common.h | 443 --- openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-config.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-debug.hh | 6 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h | 82 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.cc | 93 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.h | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.hh | 60 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.cc | 228 + openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.h | 16 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.hh | 6 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.cc | 611 ++++- openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.h | 97 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.hh | 359 ++- openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ft.cc | 348 +- openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ft.h | 4 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh | 30 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh | 6 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-object.hh | 6 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh | 14 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh | 10 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc | 10 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh | 18 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh | 83 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc | 8 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc | 1 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc | 397 +-- openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh | 8 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh | 55 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh | 22 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc | 17 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh | 17 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh | 18 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc | 14 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc | 9 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc | 44 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh | 4 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc | 6 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh | 10 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-outline.cc | 6 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-outline.hh | 1 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.cc | 207 + openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.hh | 117 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc | 95 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh | 11 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.cc | 46 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.h | 16 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.hh | 16 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-script-list.h | 484 ++++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh | 9 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-set.hh | 1 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-shape.cc | 6 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-static.cc | 1 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc | 2 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc | 772 ------ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh | 70 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset.cc | 104 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset.h | 24 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-vector.hh | 9 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-version.h | 6 openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb.hh | 55 openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/PlatformGraphicsInfo.java | 5 openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java | 7 openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java | 64 openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java | 27 openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java | 9 openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java | 85 openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java | 18 openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/XdgDesktopPortal.java | 96 openjdk-21-21.0.9+10/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h | 7 openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c | 346 ++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c | 20 openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c | 7 openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h | 5 openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h | 5 openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c | 217 + openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h | 4 openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c | 515 +++- openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.h | 31 openjdk-21-21.0.9+10/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h | 4 openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java | 23 openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java | 16 openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java | 115 openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java | 22 openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java | 22 openjdk-21-21.0.9+10/src/java.desktop/windows/classes/sun/awt/windows/WClipboard.java | 52 openjdk-21-21.0.9+10/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp | 45 openjdk-21-21.0.9+10/src/java.management/share/classes/javax/management/remote/package.html | 30 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java | 16 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java | 2 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java | 12 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/ECDSAUtils.java | 40 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java | 3 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureECDSA.java | 104 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java | 40 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/DEREncodedKeyValue.java | 6 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java | 15 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/ECKeyValue.java | 53 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/resource/xmlsecurity_de.properties | 2 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/XMLSignature.java | 17 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/Constants.java | 6 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/ElementProxy.java | 3 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/SignatureMethod.java | 2 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfoFactory.java | 2 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java | 77 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java | 104 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignatureFactory.java | 8 openjdk-21-21.0.9+10/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java | 2 openjdk-21-21.0.9+10/src/java.xml.crypto/share/legal/santuario.md | 6 openjdk-21-21.0.9+10/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLSchemaMessages.properties | 1 openjdk-21-21.0.9+10/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderFactoryImpl.java | 26 openjdk-21-21.0.9+10/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java | 12 openjdk-21-21.0.9+10/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java | 9 openjdk-21-21.0.9+10/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java | 12 openjdk-21-21.0.9+10/src/java.xml/share/classes/jdk/xml/internal/JdkXmlUtils.java | 18 openjdk-21-21.0.9+10/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java | 16 openjdk-21-21.0.9+10/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java | 40 openjdk-21-21.0.9+10/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java | 19 openjdk-21-21.0.9+10/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c | 51 openjdk-21-21.0.9+10/src/jdk.charsets/share/classes/sun/nio/cs/ext/EUC_JP_Open.java.template | 5 openjdk-21-21.0.9+10/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java | 3 openjdk-21-21.0.9+10/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java | 7 openjdk-21-21.0.9+10/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java | 5 openjdk-21-21.0.9+10/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java | 19 openjdk-21-21.0.9+10/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java | 4 openjdk-21-21.0.9+10/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java | 45 openjdk-21-21.0.9+10/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java | 4 openjdk-21-21.0.9+10/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp | 12 openjdk-21-21.0.9+10/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java | 6 openjdk-21-21.0.9+10/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java | 5 openjdk-21-21.0.9+10/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/SimpleFileServerImpl.java | 10 openjdk-21-21.0.9+10/src/jdk.jartool/share/classes/sun/tools/jar/Main.java | 13 openjdk-21-21.0.9+10/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-ui.css | 9 openjdk-21-21.0.9+10/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-ui.js | 168 - openjdk-21-21.0.9+10/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-ui.min.css | 8 openjdk-21-21.0.9+10/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-ui.min.js | 8 openjdk-21-21.0.9+10/src/jdk.javadoc/share/legal/jqueryUI.md | 4 openjdk-21-21.0.9+10/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java | 3 openjdk-21-21.0.9+10/src/jdk.jfr/share/classes/jdk/jfr/internal/query/FieldBuilder.java | 7 openjdk-21-21.0.9+10/test/failure_handler/src/share/conf/windows.properties | 16 openjdk-21-21.0.9+10/test/hotspot/gtest/gc/shared/test_bufferNodeAllocator.cpp | 32 openjdk-21-21.0.9+10/test/hotspot/gtest/gc/shared/test_workerDataArray.cpp | 10 openjdk-21-21.0.9+10/test/hotspot/gtest/os/linux/test_cgroupSubsystem_linux.cpp | 204 - openjdk-21-21.0.9+10/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp | 557 ++++ openjdk-21-21.0.9+10/test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp | 86 openjdk-21-21.0.9+10/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/ProblemList-Virtual.txt | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/ProblemList-Xcomp.txt | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/ProblemList.txt | 7 openjdk-21-21.0.9+10/test/hotspot/jtreg/TEST.ROOT | 3 openjdk-21-21.0.9+10/test/hotspot/jtreg/TEST.groups | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/applications/jcstress/README | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/applications/jcstress/TestGenerator.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/applications/scimark/Scimark.java | 58 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceRefersToTests.java | 156 + openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseMD5IntrinsicsOptionOnUnsupportedCPU.java | 13 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnUnsupportedCPU.java | 15 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnUnsupportedCPU.java | 15 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnUnsupportedCPU.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnUnsupportedCPU.java | 15 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHAOptionOnUnsupportedCPU.java | 15 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java | 106 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForUnsupportedAArch64CPU.java | 114 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForUnsupportedCPU.java | 114 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForUnsupportedRISCV64CPU.java | 115 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForUnsupportedX86CPU.java | 110 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/jsr292/CallSiteDepContextTest.java | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java | 63 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/membars/DekkerTest.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/rangechecks/TestSunkRangeFromPreLoopRCE.java | 81 openjdk-21-21.0.9+10/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/cgroup/PlainRead.java | 78 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/cgroup/TestContainerized.java | 48 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/DockerBasicTest.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/ShareTmpDir.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestCPUSets.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestContainerInfo.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestJFREvents.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestMisc.java | 5 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/docker/TestPids.java | 1 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/systemd/HelloSystemd.java | 28 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/systemd/SystemdMemoryAwarenessTest.java | 85 openjdk-21-21.0.9+10/test/hotspot/jtreg/containers/systemd/TEST.properties | 24 openjdk-21-21.0.9+10/test/hotspot/jtreg/gc/TestObjectAlignmentCardSize.java | 63 openjdk-21-21.0.9+10/test/hotspot/jtreg/gc/arguments/TestUseCompressedOopsFlagsWithUlimit.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/gc/shenandoah/compiler/TestLostAntiDependencyAtExpansion.java | 67 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassInitErrors/InitExceptionUnloadTest.java | 9 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassUnload/DictionaryDependsTest.java | 12 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassUnload/KeepAliveClass.java | 14 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassUnload/KeepAliveClassLoader.java | 13 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassUnload/KeepAliveObject.java | 13 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassUnload/KeepAliveSoftReference.java | 6 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassUnload/SuperDependsTest.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassUnload/UnloadInterfaceTest.java | 11 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java | 8 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java | 7 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/LoadClass/LoadClassNegative.java | 13 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/Thread/TestBreakSignalThreadDump.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/XCheckJniJsig/XCheckJSig.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java | 5 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java | 167 + openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java | 27 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java | 37 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/HelloUnload.java | 8 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java | 8 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/classFileParserBug/TestEmptyBootstrapMethodsAttr.java | 16 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/logging/LoaderConstraintsTest.java | 17 openjdk-21-21.0.9+10/test/hotspot/jtreg/runtime/os/HugePageConfiguration.java | 3 openjdk-21-21.0.9+10/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/gc/gctests/PhantomReference/phantom001/phantom001.java | 7 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/metaspace/share/TriggerUnloadingWithFullGC.java | 36 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/metaspace/share/TriggerUnloadingWithWhiteBox.java | 38 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowTest/ShrinkGrowTest.java | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/metaspace/staticReferences/StaticReferences.java | 6 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/StressHierarchyBaseClass.java | 6 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java | 8 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java | 11 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java | 13 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java | 8 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetErrorName/geterrname002/TestDescription.java | 5 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetThreadCpuTime/thrcputime002/thrcputime002.cpp | 12 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003/TestDescription.java | 7 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetVerboseFlag/setvrbflag002/TestDescription.java | 5 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI02/bi02t001/bi02t001.cpp | 17 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI03/bi03t001/bi03t001.cpp | 16 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryNotificationInfo/from/from001.java | 89 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryNotificationInfo/from/from001/TestDescription.java | 11 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageUtils.java | 11 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java | 11 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java | 6 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Debugee.java | 7 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress001.cpp | 6 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress003.cpp | 18 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress004.cpp | 10 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress006.cpp | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress007.cpp | 2 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings/TestDescription.java | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_NonbranchyTree/TestDescription.java | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_ArrayOf/TestDescription.java | 4 openjdk-21-21.0.9+10/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_InternedStrings/TestDescription.java | 4 openjdk-21-21.0.9+10/test/jdk/ProblemList.txt | 11 openjdk-21-21.0.9+10/test/jdk/TEST.ROOT | 3 openjdk-21-21.0.9+10/test/jdk/TEST.groups | 28 openjdk-21-21.0.9+10/test/jdk/build/AbsPathsInImage.java | 4 openjdk-21-21.0.9+10/test/jdk/com/sun/java/swing/plaf/motif/MenuItem/AcceleratorDelimiter/MotifLAFMenuAcceleratorDelimiter.java | 95 openjdk-21-21.0.9+10/test/jdk/com/sun/java/swing/plaf/motif/SplitPane/4141400/bug4141400.java | 71 openjdk-21-21.0.9+10/test/jdk/com/sun/java/swing/plaf/windows/MenuItem/4685843/bug4685843.java | 87 openjdk-21-21.0.9+10/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java | 7 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/SelCacheTest.java | 83 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/Test1.java | 81 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/Test12.java | 86 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/Test13.java | 70 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/Test9.java | 111 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/Test9a.java | 107 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/TestLogging.java | 24 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/docs/test1/largefile.txt | 2 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/docs/test1/smallfile.txt | 1 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java | 21 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePortNotSpecifiedTest.java | 5 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java | 23 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLineNegativeTest.java | 21 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePortNotSpecifiedTest.java | 5 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/CommandLinePositiveTest.java | 23 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/IPv6BoundHost.java | 100 openjdk-21-21.0.9+10/test/jdk/com/sun/net/httpserver/simpleserver/jwebserver/MaxRequestTimeTest.java | 5 openjdk-21-21.0.9+10/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java | 12 openjdk-21-21.0.9+10/test/jdk/java/awt/Clipboard/ConcurrentClipboardAccessTest.java | 77 openjdk-21-21.0.9+10/test/jdk/java/awt/Component/UpdatingBootTime.java | 98 openjdk-21-21.0.9+10/test/jdk/java/awt/Component/UpdatingBootTime/UpdatingBootTime.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/Component/UpdatingBootTime/UpdatingBootTime.java | 222 - openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest.java | 90 openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.html | 32 openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.java | 226 - openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/BrowseTest.java | 19 openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java | 35 openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/OpenTest.java | 21 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories.java | 90 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.html | 47 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.java | 82 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages.java | 79 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.html | 47 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.java | 84 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest.java | 79 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.java | 239 -- openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest.java | 142 + openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.java | 246 -- openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest.java | 105 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.html | 45 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.java | 96 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode.java | 106 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.java | 289 -- openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest.java | 74 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.java | 226 - openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest.java | 91 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.html | 45 openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.java | 89 openjdk-21-21.0.9+10/test/jdk/java/awt/FontMetrics/ExtremeFontSizeTest.java | 112 openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/DisposeParentGC/DisposeParentGC.java | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.java | 251 -- openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/MiscUndecorated/ActiveAWTWindowTest.java | 23 openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java | 23 openjdk-21-21.0.9+10/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.html | 40 openjdk-21-21.0.9+10/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.java | 103 openjdk-21-21.0.9+10/test/jdk/java/awt/Label/ContainerValidateTest.java | 169 + openjdk-21-21.0.9+10/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java | 102 openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/ButtonRepaint.java | 30 openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/CheckboxRepaint.java | 29 openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/LabelRepaint.java | 24 openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/ListRepaint.java | 45 openjdk-21-21.0.9+10/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java | 285 -- openjdk-21-21.0.9+10/test/jdk/java/awt/TextField/SetEchoCharTest.java | 178 + openjdk-21-21.0.9+10/test/jdk/java/awt/TextField/SetEchoCharWordOpsTest.java | 90 openjdk-21-21.0.9+10/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.html | 48 openjdk-21-21.0.9+10/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.java | 116 openjdk-21-21.0.9+10/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.java | 228 - openjdk-21-21.0.9+10/test/jdk/java/awt/event/ClickEventsTest.java | 133 + openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java | 71 openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java | 126 + openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/KeyCharTest/KeyCharTest.java | 52 openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/NumpadTest.java | 119 + openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel.java | 131 + openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.html | 43 openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.java | 251 -- openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java | 438 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/DragToLightweightTest.java | 146 + openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseEnterTest.java | 175 + openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java | 307 ++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java | 181 + openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseRButTest.java | 97 openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java | 78 openjdk-21-21.0.9+10/test/jdk/java/awt/event/StressTest/LargeAWTEventMulticasterTest.java | 96 openjdk-21-21.0.9+10/test/jdk/java/awt/event/WindowActivatedEventTest.java | 169 + openjdk-21-21.0.9+10/test/jdk/java/awt/font/TextLayout/MyanmarTextTest.java | 45 openjdk-21-21.0.9+10/test/jdk/java/awt/im/4490692/bug4490692.html | 61 openjdk-21-21.0.9+10/test/jdk/java/awt/im/4490692/bug4490692.java | 70 openjdk-21-21.0.9+10/test/jdk/java/awt/im/8132503/bug8132503.html | 38 openjdk-21-21.0.9+10/test/jdk/java/awt/im/8132503/bug8132503.java | 47 openjdk-21-21.0.9+10/test/jdk/java/awt/im/8148984/bug8148984.html | 38 openjdk-21-21.0.9+10/test/jdk/java/awt/im/8148984/bug8148984.java | 47 openjdk-21-21.0.9+10/test/jdk/java/awt/im/8154816/bug8154816.html | 39 openjdk-21-21.0.9+10/test/jdk/java/awt/im/8154816/bug8154816.java | 47 openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMCapsTest.java | 82 openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMCommaTest.java | 78 openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMFullstopTest.java | 79 openjdk-21-21.0.9+10/test/jdk/java/awt/im/bug4490692.java | 107 openjdk-21-21.0.9+10/test/jdk/java/awt/print/PrinterJob/PrintNullString.java | 215 - openjdk-21-21.0.9+10/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java | 61 openjdk-21-21.0.9+10/test/jdk/java/beans/Introspector/DefaultMethodBeanPropertyTest.java | 462 +++ openjdk-21-21.0.9+10/test/jdk/java/lang/Class/ProtectionDomainRace.java | 80 openjdk-21-21.0.9+10/test/jdk/java/lang/ProcessBuilder/Basic.java | 12 openjdk-21-21.0.9+10/test/jdk/java/lang/management/ThreadMXBean/Locks.java | 5 openjdk-21-21.0.9+10/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java | 15 openjdk-21-21.0.9+10/test/jdk/java/math/BigInteger/ByteArrayConstructorTest.java | 148 + openjdk-21-21.0.9+10/test/jdk/java/math/BigInteger/java.base/java/math/Accessor.java | 32 openjdk-21-21.0.9+10/test/jdk/java/net/CookieHandler/B6644726.java | 9 openjdk-21-21.0.9+10/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpect100Test.java | 254 ++ openjdk-21-21.0.9+10/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java | 2 openjdk-21-21.0.9+10/test/jdk/java/net/Inet4Address/PingThis.java | 13 openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/NoLoopbackPackets.java | 17 openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/PromiscuousIPv6.java | 18 openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/SetOutgoingIf.java | 17 openjdk-21-21.0.9+10/test/jdk/java/net/ServerSocket/AnotherSelectFdsLimit.java | 7 openjdk-21-21.0.9+10/test/jdk/java/net/ServerSocket/SelectFdsLimit.java | 10 openjdk-21-21.0.9+10/test/jdk/java/net/URLConnection/UNCTest.java | 37 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/AbstractConnectTimeoutHandshake.java | 19 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/AsyncShutdownNow.java | 6 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java | 4 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java | 4 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/HttpClientShutdown.java | 8 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ShutdownNow.java | 6 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/BasicTest.java | 45 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java | 45 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/ServerPush.java | 20 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java | 14 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/TestUtil.java | 85 openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java | 23 openjdk-21-21.0.9+10/test/jdk/java/net/ipv6tests/TcpTest.java | 9 openjdk-21-21.0.9+10/test/jdk/java/nio/charset/Charset/Contains.java | 27 openjdk-21-21.0.9+10/test/jdk/java/security/cert/CertificateFactory/SlowStream.java | 85 openjdk-21-21.0.9+10/test/jdk/java/security/cert/CertificateFactory/slowstream.sh | 54 openjdk-21-21.0.9+10/test/jdk/java/text/Format/MessageFormat/SerializationTest.java | 10 openjdk-21-21.0.9+10/test/jdk/java/util/Currency/CurrencyTest.java | 56 openjdk-21-21.0.9+10/test/jdk/java/util/Currency/ISO4217-list-one.txt | 12 openjdk-21-21.0.9+10/test/jdk/java/util/Currency/ValidateISO4217.java | 4 openjdk-21-21.0.9+10/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java | 28 openjdk-21-21.0.9+10/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java | 2 openjdk-21-21.0.9+10/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java | 8 openjdk-21-21.0.9+10/test/jdk/java/util/zip/EntryCount64k.java | 11 openjdk-21-21.0.9+10/test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java | 93 openjdk-21-21.0.9+10/test/jdk/javax/accessibility/TestPopupMenuChildCount.java | 109 openjdk-21-21.0.9+10/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java | 63 openjdk-21-21.0.9+10/test/jdk/javax/management/remote/mandatory/notif/ListenerScaleTest.java | 6 openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java | 3 openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java | 64 openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java | 18 openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java | 75 openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java | 6 openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/TLSBase.java | 230 + openjdk-21-21.0.9+10/test/jdk/javax/sound/midi/File/SMFInterruptedRunningStatus.java | 144 + openjdk-21-21.0.9+10/test/jdk/javax/swing/JColorChooser/Test6977726.java | 9 openjdk-21-21.0.9+10/test/jdk/javax/swing/JComboBox/6559152/bug6559152.java | 8 openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.html | 36 openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java | 98 openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.html | 40 openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java | 51 openjdk-21-21.0.9+10/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.html | 30 openjdk-21-21.0.9+10/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java | 37 openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug4187996.java | 74 openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug6471949.java | 134 + openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug6513492.java | 148 + openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java | 155 + openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.html | 36 openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.java | 52 openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.html | 32 openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.java | 212 - openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/bug4174551.java | 78 openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/bug8024926.java | 71 openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.html | 30 openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.java | 95 openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/bug7160604.java | 112 openjdk-21-21.0.9+10/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java | 258 +- openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.html | 32 openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.java | 92 openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/Test8039464.java | 95 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/4987336/bug4987336.html | 32 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/4987336/bug4987336.java | 63 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/6587742/bug6587742.html | 36 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/6587742/bug6587742.java | 130 - openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/6742358/bug6742358.html | 29 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/6742358/bug6742358.java | 92 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/bug6587742.java | 166 + openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/bug6742358.java | 106 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSplitPane/4164779/JSplitPaneKeyboardNavigationTest.java | 33 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSplitPane/8132123/bug8132123.html | 38 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSplitPane/8132123/bug8132123.java | 51 openjdk-21-21.0.9+10/test/jdk/javax/swing/JSplitPane/bug8132123.java | 77 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTabbedPane/4666224/bug4666224.html | 42 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTabbedPane/4666224/bug4666224.java | 572 ---- openjdk-21-21.0.9+10/test/jdk/javax/swing/JTabbedPane/bug4499556.java | 280 ++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JTabbedPane/bug4666224.java | 168 + openjdk-21-21.0.9+10/test/jdk/javax/swing/JTabbedPane/bug6259533.java | 82 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTable/4222153/bug4222153.html | 31 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTable/4222153/bug4222153.java | 48 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTable/TAB/TAB.html | 43 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTable/TAB/TAB.java | 169 - openjdk-21-21.0.9+10/test/jdk/javax/swing/JTable/Tab.java | 225 + openjdk-21-21.0.9+10/test/jdk/javax/swing/JTable/bug4222153.java | 117 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTextArea/bug4265784.java | 4 openjdk-21-21.0.9+10/test/jdk/javax/swing/JToolTip/4644444/bug4644444.html | 44 openjdk-21-21.0.9+10/test/jdk/javax/swing/JToolTip/4644444/bug4644444.java | 354 -- openjdk-21-21.0.9+10/test/jdk/javax/swing/JToolTip/bug4644444.java | 63 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/4314199/bug4314199.html | 31 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/4314199/bug4314199.java | 92 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/NodeChangedTest.java | 72 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/bug4118860.java | 97 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/bug4169215.java | 65 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/bug4196987.java | 70 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/bug4270654.java | 76 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/bug4314199.java | 99 openjdk-21-21.0.9+10/test/jdk/javax/swing/JTree/bug4618767.java | 121 + openjdk-21-21.0.9+10/test/jdk/javax/swing/JViewport/bug4137282.java | 90 openjdk-21-21.0.9+10/test/jdk/javax/swing/JViewport/bug4217252.java | 103 openjdk-21-21.0.9+10/test/jdk/javax/swing/JViewport/bug4237176.java | 70 openjdk-21-21.0.9+10/test/jdk/javax/swing/JViewport/bug4243479.java | 96 openjdk-21-21.0.9+10/test/jdk/javax/swing/JViewport/bug4750421.java | 69 openjdk-21-21.0.9+10/test/jdk/javax/swing/ProgressMonitor/bug4401480.java | 105 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test4243289.html | 32 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test4243289.java | 49 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test4247606.html | 33 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test4247606.java | 49 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test4252164.html | 33 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test4252164.java | 75 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test4760089.html | 33 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test4760089.java | 49 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test6910490.html | 32 openjdk-21-21.0.9+10/test/jdk/javax/swing/border/Test6910490.java | 36 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicGraphicsUtils/DrawEtchedRectTest.java | 77 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/bug4228104.java | 75 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicInternalFrameTitlePane/bug4331515.java | 68 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4220108.java | 75 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicSplitPaneDivider/AddMouseListenerTest.java | 68 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/NegativeSizeTest.java | 87 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/PreferredSizeLayoutTest.java | 71 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4305622.java | 87 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/basic/BasicToolBarUI/bug4331392.java | 73 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/metal/MenuItemUI/JavaLAFMenuAcceleratorDelimiter.java | 83 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/metal/MetalIconFactory/bug4952462.java | 98 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/metal/MetalSliderUI/4186347/bug4186347.java | 74 openjdk-21-21.0.9+10/test/jdk/javax/swing/plaf/metal/OceanTheme/4969419/bug4969419.java | 229 + openjdk-21-21.0.9+10/test/jdk/javax/swing/text/BoxView/bug6494356.java | 135 + openjdk-21-21.0.9+10/test/jdk/javax/swing/text/GlyphView/4984669/bug4984669.html | 30 openjdk-21-21.0.9+10/test/jdk/javax/swing/text/GlyphView/4984669/bug4984669.java | 55 openjdk-21-21.0.9+10/test/jdk/javax/swing/text/GlyphView/htmlUnderliningTest.java | 80 openjdk-21-21.0.9+10/test/jdk/javax/swing/text/html/TableView/7030332/bug7030332.html | 35 openjdk-21-21.0.9+10/test/jdk/javax/swing/text/html/TableView/7030332/bug7030332.java | 87 openjdk-21-21.0.9+10/test/jdk/javax/xml/crypto/dsig/GenerationTests.java | 41 openjdk-21-21.0.9+10/test/jdk/javax/xml/crypto/dsig/PSS.java | 61 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java | 45 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java | 1 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java | 1 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java | 1 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java | 1 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java | 1 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java | 1 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java | 1 openjdk-21-21.0.9+10/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java | 1 openjdk-21-21.0.9+10/test/jdk/jdk/jfr/api/metadata/annotations/TestPeriod.java | 4 openjdk-21-21.0.9+10/test/jdk/jdk/jfr/api/metadata/settingdescriptor/TestGetContentType.java | 6 openjdk-21-21.0.9+10/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java | 58 openjdk-21-21.0.9+10/test/jdk/sun/java2d/Disposer/TestDisposerRace.java | 61 openjdk-21-21.0.9+10/test/jdk/sun/java2d/loops/CopyAreaSpeed.html | 39 openjdk-21-21.0.9+10/test/jdk/sun/java2d/loops/CopyAreaSpeed.java | 243 -- openjdk-21-21.0.9+10/test/jdk/sun/net/www/protocol/file/NonLocalFtpFallback.java | 145 + openjdk-21-21.0.9+10/test/jdk/sun/net/www/protocol/http/UserCookie.java | 6 openjdk-21-21.0.9+10/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java | 4 openjdk-21-21.0.9+10/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java | 4 openjdk-21-21.0.9+10/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java | 4 openjdk-21-21.0.9+10/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java | 4 openjdk-21-21.0.9+10/test/jdk/sun/security/krb5/auto/TEST.properties | 24 openjdk-21-21.0.9+10/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java | 14 openjdk-21-21.0.9+10/test/jdk/sun/security/mscapi/AllTypes.java | 27 openjdk-21-21.0.9+10/test/jdk/sun/security/pkcs11/PKCS11Test.java | 38 openjdk-21-21.0.9+10/test/jdk/sun/security/pkcs11/SecmodTest.java | 4 openjdk-21-21.0.9+10/test/jdk/sun/security/pkcs11/tls/TestKeyMaterialMisuse.java | 87 openjdk-21-21.0.9+10/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java | 17 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/CipherSuite/AbstractDisableCipherSuites.java | 295 ++ openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4DesEdeCiphSuite.java | 275 -- openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/CipherSuite/TLSCipherSuiteWildCardMatchingDisablePartsOfCipherSuite.java | 86 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/CipherSuite/TLSCipherSuiteWildCardMatchingIllegalArgument.java | 71 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/DHKeyExchange/LegacyDHEKeyExchange.java | 6 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java | 185 + openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java | 8 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SSLSessionImpl/ResumeClientTLS12withSNI.java | 361 +++ openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SSLSocketImpl/NonAutoClose.java | 370 --- openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SSLSocketImpl/SetClientMode.java | 171 - openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java | 246 ++ openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeDTLS12.java | 58 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java | 149 + openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java | 103 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java | 231 + openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/MixingTLSUsageConstraintsWithNonTLS.java | 56 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java | 5 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS13.java | 3 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/SignatureScheme/SigSchemePropOrdering.java | 236 - openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java | 15 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustcommercialca-chain.pem | 77 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustnetworkingca-chain.pem | 76 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustpremiumca-chain.pem | 88 openjdk-21-21.0.9+10/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustpremiumeccca-chain.pem | 63 openjdk-21-21.0.9+10/test/jdk/sun/security/tools/jarsigner/compatibility/Compatibility.java | 13 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatGcCapacityOutput1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatGcCauseOutput1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatGcMetaCapacityOutput1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatGcNewCapacityOutput1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatGcNewOutput1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatGcOldCapacityOutput1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatGcOldOutput1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatGcOutput1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatLineCounts1.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatLineCounts2.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatLineCounts3.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/jstatLineCounts4.sh | 7 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/lineCounts1.awk | 2 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/lineCounts2.awk | 2 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/lineCounts3.awk | 2 openjdk-21-21.0.9+10/test/jdk/sun/tools/jstat/lineCounts4.awk | 2 openjdk-21-21.0.9+10/test/jdk/tools/jar/JarCreateFileNameTest.java | 70 openjdk-21-21.0.9+10/test/jdk/tools/jimage/JImageToolTest.java | 3 openjdk-21-21.0.9+10/test/jdk/tools/jpackage/windows/Win8301247Test.java | 29 openjdk-21-21.0.9+10/test/jdk/tools/launcher/DisableBestFitMappingTest.java | 83 openjdk-21-21.0.9+10/test/jdk/tools/launcher/Settings.java | 7 openjdk-21-21.0.9+10/test/jtreg-ext/requires/VMProps.java | 47 openjdk-21-21.0.9+10/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java | 1 openjdk-21-21.0.9+10/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsInConstantInit.java | 81 openjdk-21-21.0.9+10/test/langtools/tools/javac/lambda/LambdaExpr02.java | 2 openjdk-21-21.0.9+10/test/langtools/tools/javac/patterns/SOEDeeplyNestedBlocksTest.java | 1187 ++++++++++ openjdk-21-21.0.9+10/test/lib/jdk/test/lib/Asserts.java | 30 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/SecurityTools.java | 29 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/Utils.java | 60 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/apps/LingeredApp.java | 5 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java | 38 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/artifacts/ArtifactResolverException.java | 6 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/artifacts/JibArtifactManager.java | 4 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/classloader/ClassUnloadCommon.java | 44 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/classloader/GeneratingClassLoader.java | 10 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/classloader/GeneratingCompilingClassLoader.java | 4 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java | 10 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/containers/systemd/SystemdRunOptions.java | 152 + openjdk-21-21.0.9+10/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java | 376 +++ openjdk-21-21.0.9+10/test/lib/jdk/test/lib/format/ArrayDiff.java | 4 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/model/JavaHeapObject.java | 8 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/model/JavaStatic.java | 7 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/model/JavaThing.java | 8 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/model/Root.java | 8 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/model/Snapshot.java | 10 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/model/StackFrame.java | 8 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/model/StackTrace.java | 8 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/parser/FileReadBuffer.java | 4 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/parser/MappedReadBuffer.java | 4 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/parser/ReadBuffer.java | 3 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/hprof/parser/Reader.java | 4 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/jfr/Events.java | 4 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/jvmti/DebugeeClass.java | 8 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp | 22 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/management/ThreadMXBeanTool.java | 6 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/net/IPSupport.java | 3 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/process/ProcessTools.java | 4 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/security/CertificateBuilder.java | 23 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java | 36 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/security/XMLUtils.java | 46 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/thread/VThreadPinner.java | 6 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/thread/VThreadRunner.java | 6 openjdk-21-21.0.9+10/test/lib/jdk/test/lib/util/FileUtils.java | 38 openjdk-21-21.0.9+10/test/lib/jdk/test/whitebox/WhiteBox.java | 5 openjdk-21-21.0.9+10/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java | 19 openjdk-21-21.0.9+10/test/micro/org/openjdk/bench/java/util/stream/tasks/DataProviders.java | 43 openjdk-21-21.0.9+10/test/micro/org/openjdk/bench/java/util/stream/tasks/DictionaryWordValue/Bulk.java | 150 - openjdk-21-21.0.9+10/test/micro/org/openjdk/bench/java/util/stream/tasks/DictionaryWordValue/DictionaryProblem.java | 101 openjdk-21-21.0.9+10/test/micro/org/openjdk/bench/java/util/stream/tasks/DictionaryWordValue/Lambda.java | 89 openjdk-21-21.0.9+10/test/micro/org/openjdk/bench/java/util/stream/tasks/DictionaryWordValue/Xtras.java | 32 openjdk-21-21.0.9+10/test/micro/org/openjdk/bench/java/util/stream/tasks/PhoneCode/Bulk.java | 229 - openjdk-21-21.0.9+10/test/micro/org/openjdk/bench/java/util/stream/tasks/PhoneCode/PhoneCodeProblem.java | 105 959 files changed, 30851 insertions(+), 18396 deletions(-) gpgv: Signature made Thu Oct 23 10:22:58 2025 UTC gpgv: using RSA key B6E62F3D12AC38495C0DA90510C293B6C37C4E36 gpgv: Note: signatures using the SHA1 algorithm are rejected gpgv: Can't check signature: Bad public key dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpnz40qh5a/openjdk-21_21.0.9+10-1~deb13u1.dsc: no acceptable signature found diff -Nru openjdk-21-21.0.8+9/.jcheck/conf openjdk-21-21.0.9+10/.jcheck/conf --- openjdk-21-21.0.8+9/.jcheck/conf 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/.jcheck/conf 2025-10-13 07:49:24.000000000 +0000 @@ -1,7 +1,7 @@ [general] project=jdk-updates jbs=JDK -version=21.0.8 +version=21.0.9 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists diff -Nru openjdk-21-21.0.8+9/debian/changelog openjdk-21-21.0.9+10/debian/changelog --- openjdk-21-21.0.8+9/debian/changelog 2025-07-17 12:34:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/changelog 2025-10-23 10:14:51.000000000 +0000 @@ -1,3 +1,53 @@ +openjdk-21 (21.0.9+10-1~deb13u1) trixie-security; urgency=medium + + * Rebuild for trixie + + -- Moritz Mühlenhoff Thu, 23 Oct 2025 12:14:51 +0200 + +openjdk-21 (21.0.9+10-1) unstable; urgency=medium + + * OpenJDK 21.0.9 release, build 10. + - CVEs: + + CVE-2025-53057, 8360937: Enhance certificate handling. + + CVE-2025-53066, 8356294: Enhance Path Factories. + + CVE-2025-61748, 8359454: Enhance String handling. + + [ Vladimir Petko ] + * d/t/dependencies.sh: Relax test assertion for PC/SC library. + * d/p/jdk-8369450.patch: Fix ftbfs due to rust-coreutils date. LP: #2127120. + * d/rules: Run jtreg autopkgtests only on jtreg architectures. + * d/t/{hotspot-autopkgtest.in, jdk-autopkgtest.in}: Skip tests + that require a large amount of memory. + * d/t/{control,hotspot-autopkgtest.sh, jdk-autopkgtest.sh}: + Regenerate. + + -- Matthias Klose Wed, 22 Oct 2025 08:07:14 +0200 + +openjdk-21 (21.0.9~8ea-1) unstable; urgency=medium + + * OpenJDK 21.0.9 early access, build 8. + + [ Matthias Klose ] + * d/rules: Let the install target depend on the build target. Closes: #1105471. + + [ Vladimir Petko ] + * d/t/problems.csv: Synchronize problem list. + + -- Matthias Klose Sat, 27 Sep 2025 13:52:21 +0200 + +openjdk-21 (21.0.9~5ea-1) unstable; urgency=medium + + * OpenJDK 21.0.9 early access, build 5. + + [ Vladimir Petko ] + * d/copyright-generator/copyright-gen.py: bump copyright year. + * d/copyright: regenerate. + + [ Matthias Klose ] + * Build using GCC 15 on development releases. + + -- Matthias Klose Fri, 29 Aug 2025 12:59:33 +0200 + openjdk-21 (21.0.8+9-1) unstable; urgency=high * OpenJDK 21.0.8 release, build 9. diff -Nru openjdk-21-21.0.8+9/debian/copyright openjdk-21-21.0.9+10/debian/copyright --- openjdk-21-21.0.8+9/debian/copyright 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/copyright 2025-08-05 11:21:14.000000000 +0000 @@ -40,7 +40,7 @@ Files: * Copyright: - Copyright (c) 1996-2023 Oracle and/or its affiliates. + Copyright (c) 1996-2025 Oracle and/or its affiliates. Copyright (c) 1996-2003 Sun Microsystems, Inc. Copyright (c) 2009-2012 Red Hat, Inc. Copyright (c) 2012-2022 SAP SE. diff -Nru openjdk-21-21.0.8+9/debian/copyright-generator/copyright-gen.py openjdk-21-21.0.9+10/debian/copyright-generator/copyright-gen.py --- openjdk-21-21.0.8+9/debian/copyright-generator/copyright-gen.py 2024-03-20 23:08:28.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/copyright-generator/copyright-gen.py 2025-08-05 11:21:14.000000000 +0000 @@ -52,7 +52,7 @@ ## TODO: Can the script deduce this list? openjdk_copyrights = [ - "Copyright (c) 1996-2023 Oracle and/or its affiliates.", + "Copyright (c) 1996-2025 Oracle and/or its affiliates.", "Copyright (c) 1996-2003 Sun Microsystems, Inc.", "Copyright (c) 2009-2012 Red Hat, Inc.", "Copyright (c) 2012-2022 SAP SE.", diff -Nru openjdk-21-21.0.8+9/debian/patches/default-jvm-cfg.diff openjdk-21-21.0.9+10/debian/patches/default-jvm-cfg.diff --- openjdk-21-21.0.8+9/debian/patches/default-jvm-cfg.diff 2024-03-20 23:08:28.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/default-jvm-cfg.diff 2025-08-29 11:06:27.000000000 +0000 @@ -1,6 +1,6 @@ --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c -@@ -2047,7 +2047,7 @@ +@@ -2054,7 +2054,7 @@ jint ReadKnownVMs(const char *jvmCfgName, jboolean speculative) { FILE *jvmCfg; @@ -9,7 +9,7 @@ int cnt = 0; int lineno = 0; jlong start = 0, end = 0; -@@ -2061,6 +2061,11 @@ +@@ -2068,6 +2068,11 @@ ReadKnownVMs(const char *jvmCfgName, jbo jvmCfg = fopen(jvmCfgName, "r"); if (jvmCfg == NULL) { diff -Nru openjdk-21-21.0.8+9/debian/patches/icedtea-override-redirect-compiz.diff openjdk-21-21.0.9+10/debian/patches/icedtea-override-redirect-compiz.diff --- openjdk-21-21.0.8+9/debian/patches/icedtea-override-redirect-compiz.diff 2024-03-20 23:08:28.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/icedtea-override-redirect-compiz.diff 2025-08-29 11:06:24.000000000 +0000 @@ -1,6 +1,6 @@ --- a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java -@@ -1259,6 +1259,7 @@ +@@ -1260,6 +1260,7 @@ class XWindowPeer extends XPanelPeer imp boolean isOverrideRedirect() { return XWM.getWMID() == XWM.OPENLOOK_WM || diff -Nru openjdk-21-21.0.8+9/debian/patches/jdk-8307977-proposed.patch openjdk-21-21.0.9+10/debian/patches/jdk-8307977-proposed.patch --- openjdk-21-21.0.8+9/debian/patches/jdk-8307977-proposed.patch 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/jdk-8307977-proposed.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -Description: attach in linux hangs due to permission denied accessing /proc/pid/root - The attach API uses /proc/pid/root in order to support containers. - Dereferencing this symlink is governed by ptrace access mode PTRACE_MODE_READ_FSCREDS - which may not succeed when running as the user running the JRE. - This breaks running jcmd and jmap as the same user the JVM is running as. - Use tmpdir when pid matches ns_pid. -Author: Sebastian Lövdahl -Bug: https://bugs.openjdk.org/browse/JDK-8307977 -Bug: https://bugs.openjdk.org/browse/JDK-8226919 -Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1034601 -Last-Update: 2023-04-18 - -From 36b554e2de46d77898be4d0feae0ee2171b445bc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Sebastian=20L=C3=B6vdahl?= -Date: Tue, 18 Apr 2023 12:50:32 +0300 -Subject: [PATCH] 8226919: Fix dynamic attach in Linux for non-container - environments - ---- - .../sun/tools/attach/VirtualMachineImpl.java | 37 ++++++++++++------- - 1 file changed, 23 insertions(+), 14 deletions(-) - ---- a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java -+++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java -@@ -210,11 +210,8 @@ public class VirtualMachineImpl extends - } - - // Return the socket file for the given process. -- private File findSocketFile(int pid, int ns_pid) { -- // A process may not exist in the same mount namespace as the caller. -- // Instead, attach relative to the target root filesystem as exposed by -- // procfs regardless of namespaces. -- String root = "/proc/" + pid + "/root/" + tmpdir; -+ private File findSocketFile(int pid, int ns_pid) throws IOException { -+ String root = findTargetProcessTmpDirectory(pid, ns_pid); - return new File(root, ".java_pid" + ns_pid); - } - -@@ -230,21 +227,33 @@ public class VirtualMachineImpl extends - // Do not canonicalize the file path, or we will fail to attach to a VM in a container. - f.createNewFile(); - } catch (IOException x) { -- String root; -- if (pid != ns_pid) { -- // A process may not exist in the same mount namespace as the caller. -- // Instead, attach relative to the target root filesystem as exposed by -- // procfs regardless of namespaces. -- root = "/proc/" + pid + "/root/" + tmpdir; -- } else { -- root = tmpdir; -- } -+ String root = findTargetProcessTmpDirectory(pid, ns_pid); - f = new File(root, fn); - f.createNewFile(); - } - return f; - } - -+ private String findTargetProcessTmpDirectory(int pid, int ns_pid) throws IOException { -+ String root; -+ if (pid != ns_pid) { -+ // A process may not exist in the same mount namespace as the caller. -+ // Instead, attach relative to the target root filesystem as exposed by -+ // procfs regardless of namespaces. -+ String procRootDirectory = "/proc/" + pid + "/root"; -+ if (!Files.isReadable(Path.of(procRootDirectory))) { -+ throw new IOException( -+ String.format("Unable to access root directory %s " + -+ "of target process %d", procRootDirectory, pid)); -+ } -+ -+ root = procRootDirectory + "/" + tmpdir; -+ } else { -+ root = tmpdir; -+ } -+ return root; -+ } -+ - /* - * Write/sends the given to the target VM. String is transmitted in - * UTF-8 encoding. diff -Nru openjdk-21-21.0.8+9/debian/patches/jdk-8334502-proposed.patch openjdk-21-21.0.9+10/debian/patches/jdk-8334502-proposed.patch --- openjdk-21-21.0.8+9/debian/patches/jdk-8334502-proposed.patch 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/jdk-8334502-proposed.patch 2025-08-29 11:07:01.000000000 +0000 @@ -6,7 +6,7 @@ --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp -@@ -197,8 +197,8 @@ char* os::iso8601_time(jlong millisecond +@@ -198,8 +198,8 @@ char* os::iso8601_time(jlong millisecond abs_local_to_UTC = -(abs_local_to_UTC); } // Convert time zone offset seconds to hours and minutes. diff -Nru openjdk-21-21.0.8+9/debian/patches/jdk-8359735.patch openjdk-21-21.0.9+10/debian/patches/jdk-8359735.patch --- openjdk-21-21.0.8+9/debian/patches/jdk-8359735.patch 2025-07-17 12:32:27.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/jdk-8359735.patch 2025-08-29 11:07:10.000000000 +0000 @@ -17,7 +17,7 @@ --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java -@@ -696,7 +696,7 @@ +@@ -691,7 +691,7 @@ public class Basic { public static String path() { return path; } private static final String path = path0(); private static String path0(){ @@ -26,7 +26,7 @@ return "/bin/true"; } else { File trueExe = new File("true"); -@@ -711,7 +711,7 @@ +@@ -706,7 +706,7 @@ public class Basic { public static String path() { return path; } private static final String path = path0(); private static String path0(){ @@ -44,7 +44,7 @@ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it -@@ -295,10 +295,12 @@ +@@ -294,10 +294,12 @@ public class InfoTest { String expected = "sleep"; if (Platform.isWindows()) { expected = "sleep.exe"; diff -Nru openjdk-21-21.0.8+9/debian/patches/jdk-8369450-proposed.patch openjdk-21-21.0.9+10/debian/patches/jdk-8369450-proposed.patch --- openjdk-21-21.0.8+9/debian/patches/jdk-8369450-proposed.patch 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/jdk-8369450-proposed.patch 2025-10-09 08:03:04.000000000 +0000 @@ -0,0 +1,18 @@ +Description: [Ubuntu 25.10] openjdk fails to build due to rust-coreutils date + Add uutils as a GNU-compatible date provider. +Author: Vladimir Petko +Origin: upstream, https://github.com/openjdk/jdk/pull/27705 +Bug: https://bugs.openjdk.org/browse/JDK-8369450 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openjdk-25/+bug/2127120 +Last-Update: 2025-10-09 +--- a/make/autoconf/basic_tools.m4 ++++ b/make/autoconf/basic_tools.m4 +@@ -378,7 +378,7 @@ + + # Check if it's a GNU date compatible version + AC_MSG_CHECKING([if date is a GNU compatible version]) +- check_date=`$DATE --version 2>&1 | $GREP "GNU\|BusyBox"` ++ check_date=`$DATE --version 2>&1 | $GREP "GNU\|BusyBox\|uutils"` + if test "x$check_date" != x; then + AC_MSG_RESULT([yes]) + IS_GNU_DATE=yes diff -Nru openjdk-21-21.0.8+9/debian/patches/jdk-getAccessibleValue.diff openjdk-21-21.0.9+10/debian/patches/jdk-getAccessibleValue.diff --- openjdk-21-21.0.8+9/debian/patches/jdk-getAccessibleValue.diff 2024-03-20 23:08:28.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/jdk-getAccessibleValue.diff 2025-08-29 11:06:34.000000000 +0000 @@ -1,6 +1,6 @@ --- a/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/src/java.desktop/share/classes/javax/swing/JTree.java -@@ -5153,7 +5153,7 @@ +@@ -5153,7 +5153,7 @@ public class JTree extends JComponent im public AccessibleSelection getAccessibleSelection() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null && isLeaf) { @@ -9,7 +9,7 @@ } else { return this; } -@@ -5168,7 +5168,7 @@ +@@ -5168,7 +5168,7 @@ public class JTree extends JComponent im public AccessibleText getAccessibleText() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null) { @@ -18,7 +18,7 @@ } else { return null; } -@@ -5183,7 +5183,7 @@ +@@ -5183,7 +5183,7 @@ public class JTree extends JComponent im public AccessibleValue getAccessibleValue() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null) { @@ -29,7 +29,7 @@ } --- a/src/java.desktop/share/classes/javax/swing/table/JTableHeader.java +++ b/src/java.desktop/share/classes/javax/swing/table/JTableHeader.java -@@ -1143,7 +1143,12 @@ +@@ -1143,7 +1143,12 @@ public class JTableHeader extends JCompo } public AccessibleAction getAccessibleAction() { @@ -43,7 +43,7 @@ } /** -@@ -1159,15 +1164,30 @@ +@@ -1159,15 +1164,30 @@ public class JTableHeader extends JCompo } public AccessibleSelection getAccessibleSelection() { @@ -79,7 +79,7 @@ --- a/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/src/java.desktop/share/classes/javax/swing/JTable.java -@@ -8443,7 +8443,12 @@ +@@ -8443,7 +8443,12 @@ public class JTable extends JComponent i * null */ public AccessibleSelection getAccessibleSelection() { @@ -93,7 +93,7 @@ } /** -@@ -8453,7 +8458,12 @@ +@@ -8453,7 +8458,12 @@ public class JTable extends JComponent i * @return the AccessibleText, or null */ public AccessibleText getAccessibleText() { @@ -107,7 +107,7 @@ } /** -@@ -8463,7 +8473,12 @@ +@@ -8463,7 +8473,12 @@ public class JTable extends JComponent i * @return the AccessibleValue, or null */ public AccessibleValue getAccessibleValue() { @@ -121,7 +121,7 @@ } -@@ -9223,7 +9238,12 @@ +@@ -9223,7 +9238,12 @@ public class JTable extends JComponent i * @return the AccessibleAction, or null */ public AccessibleAction getAccessibleAction() { @@ -135,7 +135,7 @@ } /** -@@ -9245,7 +9265,12 @@ +@@ -9245,7 +9265,12 @@ public class JTable extends JComponent i * null */ public AccessibleSelection getAccessibleSelection() { @@ -149,7 +149,7 @@ } /** -@@ -9255,7 +9280,12 @@ +@@ -9255,7 +9280,12 @@ public class JTable extends JComponent i * @return the AccessibleText, or null */ public AccessibleText getAccessibleText() { @@ -163,7 +163,7 @@ } /** -@@ -9265,7 +9295,12 @@ +@@ -9265,7 +9295,12 @@ public class JTable extends JComponent i * @return the AccessibleValue, or null */ public AccessibleValue getAccessibleValue() { @@ -179,7 +179,7 @@ --- a/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java +++ b/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java -@@ -6636,7 +6636,7 @@ +@@ -6633,7 +6633,7 @@ public final class AccessBridge { public AccessibleSelection getAccessibleSelection() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null && isLeaf) { @@ -188,7 +188,7 @@ } else { return this; } -@@ -6651,7 +6651,7 @@ +@@ -6648,7 +6648,7 @@ public final class AccessBridge { public AccessibleText getAccessibleText() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null) { @@ -197,7 +197,7 @@ } else { return null; } -@@ -6666,7 +6666,7 @@ +@@ -6663,7 +6663,7 @@ public final class AccessBridge { public AccessibleValue getAccessibleValue() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null) { diff -Nru openjdk-21-21.0.8+9/debian/patches/make-debug-print.diff openjdk-21-21.0.9+10/debian/patches/make-debug-print.diff --- openjdk-21-21.0.8+9/debian/patches/make-debug-print.diff 2024-03-20 23:08:28.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/make-debug-print.diff 2025-08-29 11:06:43.000000000 +0000 @@ -1,6 +1,6 @@ --- a/make/Main.gmk +++ b/make/Main.gmk -@@ -1285,6 +1285,7 @@ +@@ -1277,6 +1277,7 @@ ALL_TARGETS += default jdk images docs b # Aliases used for running tests. diff -Nru openjdk-21-21.0.8+9/debian/patches/multiple-pkcs11-library-init.diff openjdk-21-21.0.9+10/debian/patches/multiple-pkcs11-library-init.diff --- openjdk-21-21.0.8+9/debian/patches/multiple-pkcs11-library-init.diff 2024-03-20 23:08:28.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/multiple-pkcs11-library-init.diff 2025-08-29 11:06:30.000000000 +0000 @@ -7,7 +7,7 @@ --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java -@@ -52,6 +52,7 @@ +@@ -52,6 +52,7 @@ final class Config { static final int ERR_HALT = 1; static final int ERR_IGNORE_ALL = 2; static final int ERR_IGNORE_LIB = 3; @@ -15,7 +15,7 @@ // same as allowSingleThreadedModules but controlled via a system property // and applied to all providers. if set to false, no SunPKCS11 instances -@@ -1038,6 +1039,7 @@ +@@ -1047,6 +1048,7 @@ final class Config { case "ignoreAll" -> ERR_IGNORE_ALL; case "ignoreMissingLibrary" -> ERR_IGNORE_LIB; case "halt" -> ERR_HALT; @@ -25,7 +25,7 @@ if (DEBUG) { --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java -@@ -184,26 +184,37 @@ +@@ -184,26 +184,37 @@ public final class SunPKCS11 extends Aut String nssLibraryDirectory = config.getNssLibraryDirectory(); String nssSecmodDirectory = config.getNssSecmodDirectory(); boolean nssOptimizeSpace = config.getNssOptimizeSpace(); diff -Nru openjdk-21-21.0.8+9/debian/patches/series openjdk-21-21.0.9+10/debian/patches/series --- openjdk-21-21.0.8+9/debian/patches/series 2025-07-17 12:32:18.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/series 2025-10-09 08:04:05.000000000 +0000 @@ -35,7 +35,6 @@ test-use-ip-address.patch arch-add-ports.diff compile-preview.diff -jdk-8307977-proposed.patch warn-fontmanager.patch jdk-8318418.patch jdk-8295795.patch @@ -49,3 +48,4 @@ zero-alpha-workaround.diff #jdk-8347014-proposed.patch jdk-8359735.patch +jdk-8369450-proposed.patch diff -Nru openjdk-21-21.0.8+9/debian/patches/zero-alpha-workaround.diff openjdk-21-21.0.9+10/debian/patches/zero-alpha-workaround.diff --- openjdk-21-21.0.8+9/debian/patches/zero-alpha-workaround.diff 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/patches/zero-alpha-workaround.diff 2025-08-29 11:07:07.000000000 +0000 @@ -1,6 +1,6 @@ --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp -@@ -2985,6 +2985,10 @@ +@@ -2878,6 +2878,10 @@ void os::pd_commit_memory_or_exit(char* // Note that the value for MAP_FIXED_NOREPLACE differs between architectures, but all architectures // supported by OpenJDK share the same flag value. #define MAP_FIXED_NOREPLACE_value 0x100000 diff -Nru openjdk-21-21.0.8+9/debian/rules openjdk-21-21.0.9+10/debian/rules --- openjdk-21-21.0.8+9/debian/rules 2025-07-17 14:12:28.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/rules 2025-10-21 21:41:36.000000000 +0000 @@ -277,10 +277,14 @@ export CC = $(DEB_HOST_GNU_TYPE)-gcc-13 export CXX = $(DEB_HOST_GNU_TYPE)-g++-13 bd_gcc = g++-13 , -else +else ifneq (,$(filter $(distrel),trixie oracular plucky)) export CC = $(DEB_HOST_GNU_TYPE)-gcc-14 export CXX = $(DEB_HOST_GNU_TYPE)-g++-14 bd_gcc = g++-14 , +else + export CC = $(DEB_HOST_GNU_TYPE)-gcc-15 + export CXX = $(DEB_HOST_GNU_TYPE)-g++-15 + bd_gcc = g++-15 , endif # GCC 11 only @@ -1004,6 +1008,7 @@ -e 's/@jtreg_dep@/$(jtreg_dep)/g' \ -e 's/@testng_dep@/$(testng_dep)/g' \ -e 's/@basename@/$(basename)/g' \ + -e 's/@jtreg_archs@/$(jtreg_archs)/g' \ $< > $@; debian/tests/%.sh: debian/tests/%.in debian/rules @@ -1356,7 +1361,7 @@ lib_ext_dirs := $(filter-out arm hppa, $(lib_ext_dirs)) endif -install: packaging-files +install: packaging-files build dh_testdir dh_testroot dh_prep || dh_clean -k @@ -2035,7 +2040,7 @@ dh_builddeb -a $(nodemo) $(nojrez) #$(bd_options) git_project = jdk21u -git_tag = jdk-21.0.8+9 +git_tag = jdk-21.0.9+10 package_version = $(shell echo $(PKGVERSION) | sed 's/-[^-][^-]*$$//') ifneq ($(is_upstream_release),yes) package_version := $(subst +,~,$(package_version)) diff -Nru openjdk-21-21.0.8+9/debian/tests/control openjdk-21-21.0.9+10/debian/tests/control --- openjdk-21-21.0.8+9/debian/tests/control 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/control 2025-10-21 22:12:00.000000000 +0000 @@ -9,10 +9,12 @@ Tests: hotspot-autopkgtest.sh Depends: @, jtreg7 (>= 7.3.1+1~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-x11, libatk-wrapper-java, libatk-wrapper-java-jni Restrictions: allow-stderr, skippable, flaky, rw-build-tree +Architecture: amd64 i386 arm64 armhf ppc64 ppc64el riscv64 s390x alpha ia64 powerpc ppc64 sh4 x32 armel loong64 mipsel mips64el riscv64 Tests: jdk-autopkgtest.sh Depends: @, jtreg7 (>= 7.3.1+1~), libtestng7-java, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-x11, libatk-wrapper-java, libatk-wrapper-java-jni Restrictions: allow-stderr, skippable, flaky, rw-build-tree +Architecture: amd64 i386 arm64 armhf ppc64 ppc64el riscv64 s390x alpha ia64 powerpc ppc64 sh4 x32 armel loong64 mipsel mips64el riscv64 Tests: dependencies.sh Depends: @, build-essential, bash diff -Nru openjdk-21-21.0.8+9/debian/tests/control.in openjdk-21-21.0.9+10/debian/tests/control.in --- openjdk-21-21.0.8+9/debian/tests/control.in 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/control.in 2025-10-17 07:19:14.000000000 +0000 @@ -9,10 +9,12 @@ Tests: hotspot-autopkgtest.sh Depends: @, @jtreg_dep@, @testng_dep@, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-x11, libatk-wrapper-java, libatk-wrapper-java-jni Restrictions: allow-stderr, skippable, flaky, rw-build-tree +Architecture: @jtreg_archs@ Tests: jdk-autopkgtest.sh Depends: @, @jtreg_dep@, @testng_dep@, build-essential, bash, lsb-release, xfwm4, xvfb, xauth, dbus-x11, libatk-wrapper-java, libatk-wrapper-java-jni Restrictions: allow-stderr, skippable, flaky, rw-build-tree +Architecture: @jtreg_archs@ Tests: dependencies.sh Depends: @, build-essential, bash diff -Nru openjdk-21-21.0.8+9/debian/tests/dependencies.sh openjdk-21-21.0.9+10/debian/tests/dependencies.sh --- openjdk-21-21.0.8+9/debian/tests/dependencies.sh 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/dependencies.sh 2025-10-07 08:00:01.000000000 +0000 @@ -27,7 +27,7 @@ ${jdk_path}/bin/java -Djava.security.debug=all \ -cp . ${AUTOPKGTEST_TMP}/Test.java > ${AUTOPKGTEST_TMP}/dependencies-pcsc.log 2>&1 -if grep "pcsc: Using PC/SC library" ${AUTOPKGTEST_TMP}/dependencies-pcsc.log; then +if grep "Using PC/SC library" ${AUTOPKGTEST_TMP}/dependencies-pcsc.log; then echo "Test passed." else cat ${AUTOPKGTEST_TMP}/dependencies-pcsc.log diff -Nru openjdk-21-21.0.8+9/debian/tests/hotspot-autopkgtest.in openjdk-21-21.0.9+10/debian/tests/hotspot-autopkgtest.in --- openjdk-21-21.0.8+9/debian/tests/hotspot-autopkgtest.in 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/hotspot-autopkgtest.in 2025-10-17 07:19:14.000000000 +0000 @@ -22,6 +22,7 @@ problem_list=${AUTOPKGTEST_TMP}/problems.txt debian/tests/write-problems.sh ${problem_list} ${HOTSPOT_JTREG_PATH}/ProblemList.txt hotspot +cat debian/tests/skip-large-autopkgtest.txt >> ${problem_list} ARGS="$*" JT_DEFAULT_ARGS="-exclude:${problem_list} -k:!stress :tier1" diff -Nru openjdk-21-21.0.8+9/debian/tests/hotspot-autopkgtest.sh openjdk-21-21.0.9+10/debian/tests/hotspot-autopkgtest.sh --- openjdk-21-21.0.8+9/debian/tests/hotspot-autopkgtest.sh 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/hotspot-autopkgtest.sh 2025-10-17 07:19:14.000000000 +0000 @@ -22,6 +22,7 @@ problem_list=${AUTOPKGTEST_TMP}/problems.txt debian/tests/write-problems.sh ${problem_list} ${HOTSPOT_JTREG_PATH}/ProblemList.txt hotspot +cat debian/tests/skip-large-autopkgtest.txt >> ${problem_list} ARGS="$*" JT_DEFAULT_ARGS="-exclude:${problem_list} -k:!stress :tier1" diff -Nru openjdk-21-21.0.8+9/debian/tests/jdk-autopkgtest.in openjdk-21-21.0.9+10/debian/tests/jdk-autopkgtest.in --- openjdk-21-21.0.8+9/debian/tests/jdk-autopkgtest.in 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/jdk-autopkgtest.in 2025-10-17 07:19:14.000000000 +0000 @@ -43,6 +43,7 @@ problem_list=${AUTOPKGTEST_TMP}/problems.txt debian/tests/write-problems.sh ${problem_list} ${JDK_JTREG_PATH}/ProblemList.txt jdk +cat debian/tests/skip-large-autopkgtest.txt >> ${problem_list} ARGS="$*" JT_DEFAULT_ARGS="-exclude:${problem_list} -k:!stress :tier1" diff -Nru openjdk-21-21.0.8+9/debian/tests/jdk-autopkgtest.sh openjdk-21-21.0.9+10/debian/tests/jdk-autopkgtest.sh --- openjdk-21-21.0.8+9/debian/tests/jdk-autopkgtest.sh 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/jdk-autopkgtest.sh 2025-10-17 07:19:14.000000000 +0000 @@ -43,6 +43,7 @@ problem_list=${AUTOPKGTEST_TMP}/problems.txt debian/tests/write-problems.sh ${problem_list} ${JDK_JTREG_PATH}/ProblemList.txt jdk +cat debian/tests/skip-large-autopkgtest.txt >> ${problem_list} ARGS="$*" JT_DEFAULT_ARGS="-exclude:${problem_list} -k:!stress :tier1" diff -Nru openjdk-21-21.0.8+9/debian/tests/problems.csv openjdk-21-21.0.9+10/debian/tests/problems.csv --- openjdk-21-21.0.8+9/debian/tests/problems.csv 2025-07-17 14:12:13.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/problems.csv 2025-09-27 11:56:27.000000000 +0000 @@ -1,7 +1,7 @@ Test,Bug,Comment,Packages,Arch,Release -Error: runtime/Unsafe/InternalErrorTest.java,JDK-8335238,"To investigate, not critical for security release – JDK-22 will expire before OO release",:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,i386,:release-all +Error: runtime/Unsafe/InternalErrorTest.java,JDK-8335238,"To investigate, not critical for security release – JDK-22 will expire before OO release",:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,i386,:release-all Error: serviceability/jvmti/vthread/SuspendResume1/SuspendResume1.java#default,,"Deadlock, new failure, not critical – JDK-22 will expire before OO release",:openjdk-22,ppc64el,:release-all -FAILED: compiler/arguments/CheckCICompilerCount.java,,"Existing failure (exit code 0, expected 1)",:openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,i386,:release-all +FAILED: compiler/arguments/CheckCICompilerCount.java,,"Existing failure (exit code 0, expected 1)",:openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,i386,:release-all FAILED: compiler/codecache/MHIntrinsicAllocFailureTest.java,JDK-8298947,The issue only happens on armhf platform. ,:openjdk-17:openjdk-21,armhf,:release-all FAILED: gtest/GTestWrapper.java,,"17:UninitializedDoubleElementWorkerDataArrayTest.print_summary_on_test_vm, ",:openjdk-17:openjdk-21,i386,:release-all FAILED: java/foreign/critical/TestCritical.java,,"SEGSEGV in test, submit bug, not critical for security release",:openjdk-22,s390x,:release-all @@ -12,38 +12,38 @@ FAILED: java/foreign/TestSegments.java,,Ignore test failure in the preview api,:openjdk-21,:i386,:release-all FAILED: java/foreign/TestUpcallHighArity.java,,Ignore test failure in the preview api,:openjdk-21,:i386,:release-all FAILED: java/foreign/TestUpcallStructScope.java,,Ignore test failure in the preview api,:openjdk-21,:i386,:release-all -FAILED: java/io/File/createTempFile/TargetDirectory.java,JDK-8166162,Container issue,:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all +FAILED: java/io/File/createTempFile/TargetDirectory.java,JDK-8166162,Container issue,:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all FAILED: java/io/File/GetXSpace.java,,"Container issue, disk space size exceeds 32 bit integer",:openjdk-17:openjdk-21:openjdk-22,:i386:armhf,:release-all -FAILED: java/nio/channels/FileChannel/directio/DirectIOTest.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/channels/FileChannel/directio/PreadDirect.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/channels/FileChannel/directio/PwriteDirect.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/channels/FileChannel/directio/ReadDirect.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/channels/FileChannel/directio/WriteDirect.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/attribute/AclFileAttributeView/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all +FAILED: java/nio/channels/FileChannel/directio/DirectIOTest.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/channels/FileChannel/directio/PreadDirect.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/channels/FileChannel/directio/PwriteDirect.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/channels/FileChannel/directio/ReadDirect.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/channels/FileChannel/directio/WriteDirect.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/attribute/AclFileAttributeView/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all FAILED: java/nio/file/attribute/BasicFileAttributeView/CreationTime.java,JDK-8166162,Container issue,:openjdk-22,i386,:release-all -FAILED: java/nio/file/attribute/BasicFileAttributeView/SetTimesNanos.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/attribute/DosFileAttributeView/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/attribute/PosixFileAttributeView/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/Files/CheckPermissions.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/Files/CopyAndMove.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/Files/CopyMoveVariations.java,JDK-8166162,Container issue,:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/Files/FileAttributes.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/Files/InterruptCopy.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/Files/Misc.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/Files/TemporaryFiles.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: java/nio/file/FileStore/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: com/sun/net/httpserver/simpleserver/RootDirPermissionsTest.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all +FAILED: java/nio/file/attribute/BasicFileAttributeView/SetTimesNanos.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/attribute/DosFileAttributeView/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/attribute/PosixFileAttributeView/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/Files/CheckPermissions.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/Files/CopyAndMove.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/Files/CopyMoveVariations.java,JDK-8166162,Container issue,:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/Files/FileAttributes.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/Files/InterruptCopy.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/Files/Misc.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/Files/TemporaryFiles.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: java/nio/file/FileStore/Basic.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: com/sun/net/httpserver/simpleserver/DocRootDirPermissionsTest.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11::openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all FAILED: runtime/cds/appcds/jcmd/JCmdTestDynamicDump.java,,flaky test (?) existing comment,:openjdk-17,:arch-all,:release-all FAILED: runtime/cds/appcds/jcmd/JCmdTestFileSafety.java,,flaky test (?) existing comment,:openjdk-17,i386:arm64:amd64:ppc64el,:release-all FAILED: runtime/cds/appcds/jcmd/JCmdTestStaticDump.java,,flaky test (?) existing comment,:openjdk-17,:arch-all,:release-all FAILED: runtime/ErrorHandling/MachCodeFramesInErrorFile.java,,java.lang.InternalError: a fault occurred in a recent unsafe memory access operation in compiled Java code at java.base/java.lang.Long.toHexString(Long.java:309) at,:openjdk-17:openjdk-21,armhf,:release-all FAILED: runtime/jni/nativeStack/TestNativeStack.java,JDK-8312016,"Backport fix (do not add patch, the fix just disables the test)",:openjdk-lts:openjdk-11:openjdk-17,armhf,:release-all -FAILED: runtime/LoadClass/LongBCP.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11:openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all +FAILED: runtime/LoadClass/LongBCP.java,JDK-8166162,Container issue,:openjdk-lts:openjdk-11:openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all FAILED: runtime/Monitor/ConcurrentDeflation.java,,LockingMode == 0 (LM_MONITOR) is not fully implemented on this architectureError: Could not create the Java Virtual Machine.,:openjdk-21,armhf,:release-all -FAILED: runtime/NMT/VirtualAllocCommitMerge.java,JDK-8309698,P4 bug (existing issue),:openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,s390x,:release-all +FAILED: runtime/NMT/VirtualAllocCommitMerge.java,JDK-8309698,P4 bug (existing issue),:openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,s390x,:release-all FAILED: serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java,JDK-8303168,Existing bug,:openjdk-21,armhf,:release-all -FAILED: tools/jlink/JLinkTest.java,JDK-8240349,Bugfix failed for i386 (P4 bug),:openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:,i386,:release-all +FAILED: tools/jlink/JLinkTest.java,JDK-8240349,Bugfix failed for i386 (P4 bug),:openjdk-17:openjdk-21:openjdk-22:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,i386,:release-all FAILED: jdk/javadoc/doclet/dupThrowsTags/TestDupThrowsTags.java,,tests failing due to disable-doclint-by-default.diff (reproducible build maintainer patch),:openjdk-lts:openjdk-11,:arch-all,:release-all FAILED: jdk/javadoc/doclet/T6735320/T6735320.java,,tests failing due to disable-doclint-by-default.diff (reproducible build maintainer patch),:openjdk-lts:openjdk-11,:arch-all,:release-all FAILED: jdk/javadoc/doclet/testBadHtml/TestBadHtml.java,,tests failing due to disable-doclint-by-default.diff (reproducible build maintainer patch),:openjdk-lts:openjdk-11,:arch-all,:release-all @@ -84,6 +84,6 @@ FAILED: java/foreign/TestUpcallStack.java,, asserts due to the invalid structure size. Ignore as this is a preview API and the issue does not occur in openjdk-22. I will add it to the problemlist.,:openjdk-21,:armhf,:release-all FAILED: java/foreign/TestVarArgs.java,, asserts due to the invalid structure size. Ignore as this is a preview API and the issue does not occur in openjdk-22. I will add it to the problemlist.,:openjdk-21,:armhf,:release-all FAILED: runtime/os/TestTrimNative.java#trimNative,, java.lang.RuntimeException: We found fewer (periodic) trim lines in UL log than expected (expected at least 13 found 11). This looks like a flaky test - it asserts number of lines from the periodic trimmer e.g. src/hotspot/share/runtime/trimNativeHeap.hpp:56 which causes the test to fail due to the slow VM. Test passes locally.,:openjdk-21,:armhf,:release-all -FAILED: sun/security/util/Debug/DebugOptions.java,JDK-8339713,Stack overflow error on 32-bit platforms,:openjdk-17:openjdk-21:openjdk-23:openjdk-24:openjdk-25:,:armhf:i386:s390x,:release-all -Error: jdk/jshell/TerminalNoExecTest.java,,BackingStoreException: Couldn't get file lock - possibly because the LP (non-root) container has no home directory,:openjdk-23:openjdk-24:openjdk-25:,:arch-all,:release-all -FAILED: applications/ctw/modules/jdk_jfr.java,JDK-8352567, Unimplemented SharedRuntime::generate_jfr_write_checkpoint for S390x, :openjdk-25:,:s390x,:release-all +FAILED: sun/security/util/Debug/DebugOptions.java,JDK-8339713,Stack overflow error on 32-bit platforms,:openjdk-17:openjdk-21:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:armhf:i386:s390x,:release-all +Error: jdk/jshell/TerminalNoExecTest.java,,BackingStoreException: Couldn't get file lock - possibly because the LP (non-root) container has no home directory,:openjdk-23:openjdk-24:openjdk-25:openjdk-26:,:arch-all,:release-all +FAILED: applications/ctw/modules/jdk_jfr.java,JDK-8352567, Unimplemented SharedRuntime::generate_jfr_write_checkpoint for S390x, :openjdk-25:openjdk-26:,:s390x,:release-all diff -Nru openjdk-21-21.0.8+9/debian/tests/skip-large-autopkgtest.txt openjdk-21-21.0.9+10/debian/tests/skip-large-autopkgtest.txt --- openjdk-21-21.0.8+9/debian/tests/skip-large-autopkgtest.txt 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/debian/tests/skip-large-autopkgtest.txt 2025-10-17 07:19:14.000000000 +0000 @@ -0,0 +1,7 @@ +# The list of tier1 tests that require large amount of memory >=2G + +runtime/cds/NonJVMVariantLocation.java 0000000 generic-all +runtime/jni/checked/TestLargeUTF8Length.java 0000000 generic-all +java/foreign/TestLargeSegmentCopy.java 0000000 generic-all +java/foreign/TestStringEncodingJumbo.java 0000000 generic-all +java/util/HashMap/WhiteBoxResizeTest.java 0000000 generic-all diff -Nru openjdk-21-21.0.8+9/doc/building.html openjdk-21-21.0.9+10/doc/building.html --- openjdk-21-21.0.8+9/doc/building.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/doc/building.html 2025-10-13 07:49:24.000000000 +0000 @@ -1112,13 +1112,13 @@ Test framework. The top directory, which contains both googletest and googlemock directories, should be specified via --with-gtest. The minimum supported -version of Google Test is 1.13.0, whose source code can be obtained:

+version of Google Test is 1.14.0, whose source code can be obtained:

  • by downloading and unpacking the source bundle from here
  • -
  • or by checking out v1.13.0 tag of +href="https://github.com/google/googletest/releases/tag/v1.14.0">here
  • +
  • or by checking out v1.14.0 tag of googletest project: -git clone -b v1.13.0 https://github.com/google/googletest
  • +git clone -b v1.14.0 https://github.com/google/googletest

To execute the most basic tests (tier 1), use:

make run-test-tier1
diff -Nru openjdk-21-21.0.8+9/doc/building.md openjdk-21-21.0.9+10/doc/building.md --- openjdk-21-21.0.8+9/doc/building.md 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/doc/building.md 2025-10-13 07:49:24.000000000 +0000 @@ -881,11 +881,11 @@ Building of Hotspot Gtest suite requires the source code of Google Test framework. The top directory, which contains both `googletest` and `googlemock` directories, should be specified via `--with-gtest`. -The minimum supported version of Google Test is 1.13.0, whose source +The minimum supported version of Google Test is 1.14.0, whose source code can be obtained: - * by downloading and unpacking the source bundle from [here](https://github.com/google/googletest/releases/tag/v1.13.0) - * or by checking out `v1.13.0` tag of `googletest` project: `git clone -b v1.13.0 https://github.com/google/googletest` + * by downloading and unpacking the source bundle from [here](https://github.com/google/googletest/releases/tag/v1.14.0) + * or by checking out `v1.14.0` tag of `googletest` project: `git clone -b v1.14.0 https://github.com/google/googletest` To execute the most basic tests (tier 1), use: ``` diff -Nru openjdk-21-21.0.8+9/make/Global.gmk openjdk-21-21.0.9+10/make/Global.gmk --- openjdk-21-21.0.8+9/make/Global.gmk 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/Global.gmk 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2023, 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 @@ -52,7 +52,6 @@ $(info $(_) make docs # Create all docs) $(info $(_) make docs-jdk-api # Create just JDK javadocs) $(info $(_) make bootcycle-images # Build images twice, second time with newly built JDK) - $(info $(_) make install # Install the generated images locally) $(info $(_) make check # Run basic testing (currently tier1)) $(info $(_) make test- # Run test, e.g. test-tier1) $(info $(_) make test TEST= # Run test(s) given by TEST specification) diff -Nru openjdk-21-21.0.8+9/make/Install.gmk openjdk-21-21.0.9+10/make/Install.gmk --- openjdk-21-21.0.8+9/make/Install.gmk 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/Install.gmk 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -# -# Copyright (c) 2014, 2015, 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. 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. -# - -default: install - -include $(SPEC) - -BINARIES := $(notdir $(wildcard $(JDK_IMAGE_DIR)/bin/*)) -INSTALLDIR := openjdk-$(VERSION_SHORT) - -# Install the jdk image, in a very crude way. Not taking into -# account, how to install properly on macosx or windows etc. -install: - echo Installing jdk image into $(INSTALL_PREFIX)/jvm/$(INSTALLDIR) - echo and creating $(words $(BINARIES)) links from $(INSTALL_PREFIX)/bin into the jdk. - $(MKDIR) -p $(INSTALL_PREFIX)/jvm/$(INSTALLDIR) - $(RM) -r $(INSTALL_PREFIX)/jvm/$(INSTALLDIR)/* - $(CP) -rp $(JDK_IMAGE_DIR)/* $(INSTALL_PREFIX)/jvm/$(INSTALLDIR) - $(MKDIR) -p $(INSTALL_PREFIX)/bin - $(RM) $(addprefix $(INSTALL_PREFIX)/bin/, $(BINARIES)) - $(foreach b, $(BINARIES), $(LN) -s $(INSTALL_PREFIX)/jvm/$(INSTALLDIR)/bin/$b $(INSTALL_PREFIX)/bin/$b &&) true diff -Nru openjdk-21-21.0.8+9/make/Main.gmk openjdk-21-21.0.9+10/make/Main.gmk --- openjdk-21-21.0.8+9/make/Main.gmk 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/Main.gmk 2025-10-13 07:49:24.000000000 +0000 @@ -845,14 +845,6 @@ endif ################################################################################ -# Install targets - -$(eval $(call SetupTarget, install, \ - MAKEFILE := Install, \ - DEPS := product-images, \ -)) - -################################################################################ # # Dependency declarations between targets. # diff -Nru openjdk-21-21.0.8+9/make/RunTestsPrebuilt.gmk openjdk-21-21.0.9+10/make/RunTestsPrebuilt.gmk --- openjdk-21-21.0.8+9/make/RunTestsPrebuilt.gmk 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/RunTestsPrebuilt.gmk 2025-10-13 07:49:24.000000000 +0000 @@ -216,9 +216,9 @@ else ifeq ($(OPENJDK_TARGET_OS), windows) NUM_CORES := $(NUMBER_OF_PROCESSORS) MEMORY_SIZE := $(shell \ - $(EXPR) `wmic computersystem get totalphysicalmemory -value \ - | $(GREP) = | $(SED) 's/\\r//g' \ - | $(CUT) -d "=" -f 2-` / 1024 / 1024 \ + $(EXPR) `powershell -Command \ + "(Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory" \ + | $(SED) 's/\\r//g' ` / 1024 / 1024 \ ) endif ifeq ($(NUM_CORES), ) diff -Nru openjdk-21-21.0.8+9/make/autoconf/build-performance.m4 openjdk-21-21.0.9+10/make/autoconf/build-performance.m4 --- openjdk-21-21.0.8+9/make/autoconf/build-performance.m4 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/autoconf/build-performance.m4 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, 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 @@ -75,7 +75,8 @@ FOUND_MEM=yes elif test "x$OPENJDK_BUILD_OS" = xwindows; then # Windows, but without cygwin - MEMORY_SIZE=`wmic computersystem get totalphysicalmemory -value | grep = | cut -d "=" -f 2-` + MEMORY_SIZE=`powershell -Command \ + "(Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory" | $SED 's/\\r//g' ` MEMORY_SIZE=`expr $MEMORY_SIZE / 1024 / 1024` FOUND_MEM=yes fi diff -Nru openjdk-21-21.0.8+9/make/autoconf/flags-cflags.m4 openjdk-21-21.0.9+10/make/autoconf/flags-cflags.m4 --- openjdk-21-21.0.8+9/make/autoconf/flags-cflags.m4 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/autoconf/flags-cflags.m4 2025-10-13 07:49:24.000000000 +0000 @@ -387,7 +387,7 @@ C_O_FLAG_DEBUG="-Od" C_O_FLAG_DEBUG_JVM="" C_O_FLAG_NONE="-Od" - C_O_FLAG_SIZE="-Os" + C_O_FLAG_SIZE="-O1" fi # Now copy to C++ flags diff -Nru openjdk-21-21.0.8+9/make/autoconf/lib-tests.m4 openjdk-21-21.0.9+10/make/autoconf/lib-tests.m4 --- openjdk-21-21.0.8+9/make/autoconf/lib-tests.m4 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/autoconf/lib-tests.m4 2025-10-13 07:49:24.000000000 +0000 @@ -29,7 +29,7 @@ # Minimum supported versions JTREG_MINIMUM_VERSION=7.3.1 -GTEST_MINIMUM_VERSION=1.13.0 +GTEST_MINIMUM_VERSION=1.14.0 ############################################################################### # diff -Nru openjdk-21-21.0.8+9/make/autoconf/spec.gmk.in openjdk-21-21.0.9+10/make/autoconf/spec.gmk.in --- openjdk-21-21.0.8+9/make/autoconf/spec.gmk.in 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/autoconf/spec.gmk.in 2025-10-13 07:49:24.000000000 +0000 @@ -819,57 +819,6 @@ #################################################### # -# INSTALLATION -# - -# Common prefix for all installed files. Defaults to /usr/local, -# but /opt/myjdk is another common version. -INSTALL_PREFIX=@prefix@ - -# Directories containing architecture-dependent files should be relative to exec_prefix -INSTALL_EXECPREFIX=@exec_prefix@ - -# java,javac,javap etc are installed here. -INSTALL_BINDIR=@bindir@ - -# Read only architecture-independent data -INSTALL_DATADIR=@datadir@ - -# Root of above. -INSTALL_DATAROOTDIR=@datarootdir@ - -# Doc files, other than info and man. -INSTALL_DOCDIR=@docdir@ - -# Html documentation -INSTALL_HTMLDIR=@htmldir@ - -# Installing C header files, JNI headers for example. -INSTALL_INCLUDEDIR=@includedir@ - -# Installing library files.... -INSTALL_INCLUDEDIR=@libdir@ - -# Executables that other programs run. -INSTALL_LIBEXECDIR=@libexecdir@ - -# Locale-dependent but architecture-independent data, such as message catalogs. -INSTALL_LOCALEDIR=@localedir@ - -# Modifiable single-machine data -INSTALL_LOCALSTATEDIR=@localstatedir@ - -# Man pages -INSTALL_MANDIR=@mandir@ - -# Modifiable architecture-independent data. -INSTALL_SHAREDSTATEDIR=@sharedstatedir@ - -# Read-only single-machine data -INSTALL_SYSCONFDIR=@sysconfdir@ - -#################################################### -# # Libraries # diff -Nru openjdk-21-21.0.8+9/make/conf/github-actions.conf openjdk-21-21.0.9+10/make/conf/github-actions.conf --- openjdk-21-21.0.8+9/make/conf/github-actions.conf 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/conf/github-actions.conf 2025-10-13 07:49:24.000000000 +0000 @@ -25,7 +25,7 @@ # Versions and download locations for dependencies used by GitHub Actions (GHA) -GTEST_VERSION=1.13.0 +GTEST_VERSION=1.14.0 JTREG_VERSION=7.3.1+1 LINUX_X64_BOOT_JDK_EXT=tar.gz diff -Nru openjdk-21-21.0.8+9/make/conf/jib-profiles.js openjdk-21-21.0.9+10/make/conf/jib-profiles.js --- openjdk-21-21.0.8+9/make/conf/jib-profiles.js 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/conf/jib-profiles.js 2025-10-13 07:49:24.000000000 +0000 @@ -1267,7 +1267,7 @@ gtest: { organization: common.organization, ext: "tar.gz", - revision: "1.13.0+1.0" + revision: "1.14.0+1.0" }, libffi: { diff -Nru openjdk-21-21.0.8+9/make/conf/version-numbers.conf openjdk-21-21.0.9+10/make/conf/version-numbers.conf --- openjdk-21-21.0.8+9/make/conf/version-numbers.conf 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/conf/version-numbers.conf 2025-10-13 07:49:24.000000000 +0000 @@ -28,12 +28,12 @@ DEFAULT_VERSION_FEATURE=21 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=8 +DEFAULT_VERSION_UPDATE=9 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2025-07-15 +DEFAULT_VERSION_DATE=2025-10-21 DEFAULT_VERSION_CLASSFILE_MAJOR=65 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 diff -Nru openjdk-21-21.0.8+9/make/data/hotspot-symbols/symbols-linux openjdk-21-21.0.9+10/make/data/hotspot-symbols/symbols-linux --- openjdk-21-21.0.8+9/make/data/hotspot-symbols/symbols-linux 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/data/hotspot-symbols/symbols-linux 2025-10-13 07:49:24.000000000 +0000 @@ -22,6 +22,7 @@ # JVM_handle_linux_signal +JVM_IsContainerized JVM_IsUseContainerSupport numa_error numa_warn diff -Nru openjdk-21-21.0.8+9/make/modules/java.desktop/lib/Awt2dLibraries.gmk openjdk-21-21.0.9+10/make/modules/java.desktop/lib/Awt2dLibraries.gmk --- openjdk-21-21.0.8+9/make/modules/java.desktop/lib/Awt2dLibraries.gmk 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/modules/java.desktop/lib/Awt2dLibraries.gmk 2025-10-13 07:49:24.000000000 +0000 @@ -202,8 +202,12 @@ common/awt/systemscale \ common/font \ common/java2d/opengl \ - common/java2d/x11 \ - $(LIBPIPEWIRE_HEADER_DIRS) + common/java2d/x11 + + # exclude pipewire from the AIX build, no Wayland support + ifeq ($(call isTargetOs, aix), false) + LIBAWT_XAWT_EXTRA_HEADER_DIRS += $(LIBPIPEWIRE_HEADER_DIRS) + endif LIBAWT_XAWT_CFLAGS += -DXAWT -DXAWT_HACK \ $(FONTCONFIG_CFLAGS) \ @@ -785,7 +789,7 @@ EXCLUDE_SRC_PATTERNS := $(LIBSPLASHSCREEN_EXCLUDE_SRC_PATTERNS), \ EXCLUDE_FILES := imageioJPEG.c jpegdecoder.c pngtest.c, \ EXCLUDES := $(LIBSPLASHSCREEN_EXCLUDES), \ - OPTIMIZATION := LOW, \ + OPTIMIZATION := SIZE, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBSPLASHSCREEN_CFLAGS) \ $(GIFLIB_CFLAGS) $(LIBJPEG_CFLAGS) $(PNG_CFLAGS) $(LIBZ_CFLAGS), \ EXTRA_HEADER_DIRS := $(LIBSPLASHSCREEN_HEADER_DIRS), \ diff -Nru openjdk-21-21.0.8+9/make/modules/jdk.internal.le/Lib.gmk openjdk-21-21.0.9+10/make/modules/jdk.internal.le/Lib.gmk --- openjdk-21-21.0.8+9/make/modules/jdk.internal.le/Lib.gmk 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/modules/jdk.internal.le/Lib.gmk 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, 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 @@ -34,7 +34,8 @@ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ OPTIMIZATION := LOW, \ CFLAGS := $(CXXFLAGS_JDKLIB), \ - LDFLAGS := $(LDFLAGS_JDKLIB), \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ + $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := $(JDKLIB_LIBS) $(LIBCXX), \ LIBS_windows := $(JDKLIB_LIBS) user32.lib, \ )) diff -Nru openjdk-21-21.0.8+9/make/test/BuildTestLib.gmk openjdk-21-21.0.9+10/make/test/BuildTestLib.gmk --- openjdk-21-21.0.8+9/make/test/BuildTestLib.gmk 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/make/test/BuildTestLib.gmk 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, 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 @@ -39,7 +39,6 @@ SRC := $(TEST_LIB_SOURCE_DIR)/jdk/test/whitebox/, \ BIN := $(TEST_LIB_SUPPORT)/wb_classes, \ JAR := $(TEST_LIB_SUPPORT)/wb.jar, \ - DISABLED_WARNINGS := deprecation removal preview, \ JAVAC_FLAGS := --enable-preview, \ )) diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/assembler_aarch64.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/assembler_aarch64.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/assembler_aarch64.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/assembler_aarch64.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -461,7 +461,7 @@ bool asm_util::operand_valid_for_immediate_bits(int64_t imm, unsigned nbits) { guarantee(nbits == 8 || nbits == 12, "invalid nbits value"); - uint64_t uimm = (uint64_t)uabs((jlong)imm); + uint64_t uimm = (uint64_t)g_uabs((jlong)imm); if (uimm < (UCONST64(1) << nbits)) return true; if (uimm < (UCONST64(1) << (2 * nbits)) diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/assembler_aarch64.hpp openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/assembler_aarch64.hpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/assembler_aarch64.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/assembler_aarch64.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -930,7 +930,7 @@ static const uint64_t branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M); static bool reachable_from_branch_at(address branch, address target) { - return uabs(target - branch) < branch_range; + return g_uabs(target - branch) < branch_range; } // Unconditional branch (immediate) diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -2894,7 +2894,7 @@ if (fits) { (this->*insn1)(Rd, Rn, imm); } else { - if (uabs(imm) < (1 << 24)) { + if (g_uabs(imm) < (1 << 24)) { (this->*insn1)(Rd, Rn, imm & -(1 << 12)); (this->*insn1)(Rd, Rd, imm & ((1 << 12)-1)); } else { diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1130,7 +1130,7 @@ void copy_memory_small(DecoratorSet decorators, BasicType type, Register s, Register d, Register count, int step) { bool is_backwards = step < 0; - size_t granularity = uabs(step); + size_t granularity = g_uabs(step); int direction = is_backwards ? -1 : 1; Label Lword, Lint, Lshort, Lbyte; @@ -1189,7 +1189,7 @@ Register s, Register d, Register count, int step) { copy_direction direction = step < 0 ? copy_backwards : copy_forwards; bool is_backwards = step < 0; - unsigned int granularity = uabs(step); + unsigned int granularity = g_uabs(step); const Register t0 = r3, t1 = r4; // <= 80 (or 96 for SIMD) bytes do inline. Direction doesn't matter because we always diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1135,6 +1135,7 @@ // Get the value we will store __ ldr(r0, at_tos()); // Now store using the appropriate barrier + // Clobbers: r10, r11, r3 do_oop_store(_masm, element_address, r0, IS_ARRAY); __ b(done); @@ -1143,6 +1144,7 @@ __ profile_null_seen(r2); // Store a null + // Clobbers: r10, r11, r3 do_oop_store(_masm, element_address, noreg, IS_ARRAY); // Pop stack arguments @@ -2774,6 +2776,7 @@ __ pop(atos); if (!is_static) pop_and_check_object(obj); // Store into the field + // Clobbers: r10, r11, r3 do_oop_store(_masm, field, r0, IN_HEAP); if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_aputfield, bc, r1, true, byte_no); @@ -2973,8 +2976,8 @@ // Must prevent reordering of the following cp cache loads with bytecode load __ membar(MacroAssembler::LoadLoad); - // test for volatile with r3 - __ ldrw(r3, Address(r2, in_bytes(base + + // test for volatile with r5 + __ ldrw(r5, Address(r2, in_bytes(base + ConstantPoolCacheEntry::flags_offset()))); // replace index with field offset from cache entry @@ -2982,7 +2985,7 @@ { Label notVolatile; - __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(r5, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); __ bind(notVolatile); } @@ -2998,6 +3001,7 @@ // access field switch (bytecode()) { case Bytecodes::_fast_aputfield: + // Clobbers: r10, r11, r3 do_oop_store(_masm, field, r0, IN_HEAP); break; case Bytecodes::_fast_lputfield: @@ -3030,7 +3034,7 @@ { Label notVolatile; - __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); + __ tbz(r5, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore); __ bind(notVolatile); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/frame_ppc.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/frame_ppc.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/frame_ppc.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/frame_ppc.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2023 SAP SE. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. 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 @@ -191,6 +191,15 @@ return false; } + if (sender_pc() == nullptr) { + // Likely the return pc was not yet stored to stack. We rather discard this + // sample also because we would hit an assertion in frame::setup(). We can + // find any other random value if the return pc was not yet stored to + // stack. We rely on consistency checks to handle this (see + // e.g. find_initial_Java_frame()) + return false; + } + return true; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/gc/x/xGlobals_ppc.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -82,12 +82,12 @@ // Maximum value as per spec (Power ISA v2.07): 2 ^ 60 bytes, i.e. 1 EiB (exbibyte) static const unsigned int MAXIMUM_MAX_ADDRESS_BIT = 60; -// Most modern power processors provide an address space with not more than 45 bit addressable bit, -// that is an address space of 32 TiB in size. -static const unsigned int DEFAULT_MAX_ADDRESS_BIT = 45; - -// Minimum value returned, if probing fails: 64 GiB -static const unsigned int MINIMUM_MAX_ADDRESS_BIT = 36; +// Default value if probing is not implemented for a certain platform +// Max address bit is restricted by implicit assumptions in the code, for instance +// the bit layout of XForwardingEntry or Partial array entry (see XMarkStackEntry) in mark stack +static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; +// Minimum value returned, if probing fails +static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; // Determines the highest addressable bit of the virtual address space (depends on platform) // by trying to interact with memory in that address range, diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -35,9 +35,11 @@ #include #endif // LINUX -// Default value if probing is not implemented for a certain platform: 128TB -static const size_t DEFAULT_MAX_ADDRESS_BIT = 47; -// Minimum value returned, if probing fails: 64GB +// Default value if probing is not implemented for a certain platform +// Max address bit is restricted by implicit assumptions in the code, for instance +// the bit layout of ZForwardingEntry or Partial array entry (see ZMarkStackEntry) in mark stack +static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; +// Minimum value returned, if probing fail static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; static size_t probe_valid_max_address_bit() { @@ -92,10 +94,15 @@ size_t ZPlatformAddressOffsetBits() { const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; +#ifdef ADDRESS_SANITIZER + // The max supported value is 44 because of other internal data structures. + return MIN2(valid_max_address_offset_bits, (size_t)44); +#else const size_t min_address_offset_bits = max_address_offset_bits - 2; const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); const size_t address_offset_bits = log2i_exact(address_offset); return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); +#endif } size_t ZPlatformAddressHeapBaseShift() { diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/methodHandles_ppc.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/methodHandles_ppc.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/methodHandles_ppc.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/methodHandles_ppc.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -360,7 +360,9 @@ ? -1 // enforce receiver null check : oopDesc::klass_offset_in_bytes(); // regular null-checking behavior - __ null_check_throw(receiver_reg, klass_offset, temp1, Interpreter::throw_NullPointerException_entry()); + address NullPointerException_entry = for_compiler_entry ? StubRoutines::throw_NullPointerException_at_call_entry() + : Interpreter::throw_NullPointerException_entry(); + __ null_check_throw(receiver_reg, klass_offset, temp1, NullPointerException_entry); if (iid != vmIntrinsics::_linkToSpecial || VerifyMethodHandles) { __ load_klass(temp1_recv_klass, receiver_reg); diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1041,7 +1041,7 @@ // Need to check whether array is boolean or byte // since both types share the bastore bytecode. - __ load_klass(Rscratch, Rarray); + __ load_klass_check_null_throw(Rscratch, Rarray, Rscratch); __ lwz(Rscratch, in_bytes(Klass::layout_helper_offset()), Rscratch); int diffbit = exact_log2(Klass::layout_helper_boolean_diffbit()); __ testbitdi(CCR0, R0, Rscratch, diffbit); diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/assembler_riscv.hpp openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/assembler_riscv.hpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/assembler_riscv.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/assembler_riscv.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -2913,7 +2913,7 @@ static const unsigned long branch_range = 1 * M; static bool reachable_from_branch_at(address branch, address target) { - return uabs(target - branch) < branch_range; + return g_uabs(target - branch) < branch_range; } // Decode the given instruction, checking if it's a 16-bit compressed diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/gc/x/xGlobals_riscv.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -144,9 +144,11 @@ // * 63-48 Fixed (16-bits, always zero) // -// Default value if probing is not implemented for a certain platform: 128TB -static const size_t DEFAULT_MAX_ADDRESS_BIT = 47; -// Minimum value returned, if probing fails: 64GB +// Default value if probing is not implemented for a certain platform +// Max address bit is restricted by implicit assumptions in the code, for instance +// the bit layout of XForwardingEntry or Partial array entry (see XMarkStackEntry) in mark stack +static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; +// Minimum value returned, if probing fails static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; static size_t probe_valid_max_address_bit() { diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -37,9 +37,11 @@ #include #endif // LINUX -// Default value if probe is not implemented for a certain platform: 128TB -static const size_t DEFAULT_MAX_ADDRESS_BIT = 47; -// Minimum value returned, if probing fails: 64GB +// Default value if probing is not implemented for a certain platform +// Max address bit is restricted by implicit assumptions in the code, for instance +// the bit layout of ZForwardingEntry or Partial array entry (see ZMarkStackEntry) in mark stack +static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; +// Minimum value returned, if probing fail static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; static size_t probe_valid_max_address_bit() { diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/riscv.ad openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/riscv.ad --- openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/riscv.ad 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/riscv.ad 2025-10-13 07:49:24.000000000 +0000 @@ -2222,11 +2222,6 @@ __ mv(dst_reg, 1); %} - enc_class riscv_enc_mov_byte_map_base(iRegP dst) %{ - C2_MacroAssembler _masm(&cbuf); - __ load_byte_map_base($dst$$Register); - %} - enc_class riscv_enc_mov_n(iRegN dst, immN src) %{ C2_MacroAssembler _masm(&cbuf); Register dst_reg = as_Register($dst$$reg); @@ -2870,20 +2865,6 @@ interface(CONST_INTER); %} -// Card Table Byte Map Base -operand immByteMapBase() -%{ - // Get base of card map - predicate(BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) && - (CardTable::CardValue*)n->get_ptr() == - ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base()); - match(ConP); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - // Int Immediate: low 16-bit mask operand immI_16bits() %{ @@ -4837,18 +4818,6 @@ ins_pipe(ialu_imm); %} - -// Load Byte Map Base Constant -instruct loadByteMapBase(iRegPNoSp dst, immByteMapBase con) -%{ - match(Set dst con); - ins_cost(ALU_COST); - format %{ "mv $dst, $con\t# Byte Map Base, #@loadByteMapBase" %} - - ins_encode(riscv_enc_mov_byte_map_base(dst)); - - ins_pipe(ialu_imm); -%} // Load Narrow Pointer Constant instruct loadConN(iRegNNoSp dst, immN con) diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -917,7 +917,7 @@ void copy_memory_v(Register s, Register d, Register count, int step) { bool is_backward = step < 0; - int granularity = uabs(step); + int granularity = g_uabs(step); const Register src = x30, dst = x31, vl = x14, cnt = x15, tmp1 = x16, tmp2 = x17; assert_different_registers(s, d, cnt, vl, tmp1, tmp2); @@ -973,7 +973,7 @@ } bool is_backwards = step < 0; - int granularity = uabs(step); + int granularity = g_uabs(step); const Register src = x30, dst = x31, cnt = x15, tmp3 = x16, tmp4 = x17, tmp5 = x14, tmp6 = x13; const Register gct1 = x28, gct2 = x29, gct3 = t2; diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/templateTable_riscv.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/templateTable_riscv.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/riscv/templateTable_riscv.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/riscv/templateTable_riscv.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -123,24 +123,6 @@ return Address(esp, Interpreter::expr_offset_in_bytes(5)); } -// Miscellaneous helper routines -// Store an oop (or null) at the Address described by obj. -// If val == noreg this means store a null -static void do_oop_store(InterpreterMacroAssembler* _masm, - Address dst, - Register val, - DecoratorSet decorators) { - assert(val == noreg || val == x10, "parameter is just for looks"); - __ store_heap_oop(dst, val, x28, x29, x13, decorators); -} - -static void do_oop_load(InterpreterMacroAssembler* _masm, - Address src, - Register dst, - DecoratorSet decorators) { - __ load_heap_oop(dst, src, x28, x29, decorators); -} - Address TemplateTable::at_bcp(int offset) { assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); return Address(xbcp, offset); @@ -770,7 +752,7 @@ index_check(x10, x11); // leaves index in x11 __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop); __ shadd(x10, x11, x10, t0, LogBytesPerHeapOop); - do_oop_load(_masm, Address(x10), x10, IS_ARRAY); + __ load_heap_oop(x10, Address(x10), x28, x29, IS_ARRAY); } void TemplateTable::baload() { @@ -1082,7 +1064,7 @@ // Get the value we will store __ ld(x10, at_tos()); // Now store using the appropriate barrier - do_oop_store(_masm, element_address, x10, IS_ARRAY); + __ store_heap_oop(element_address, x10, x28, x29, x13, IS_ARRAY); __ j(done); // Have a null in x10, x13=array, x12=index. Store null at ary[idx] @@ -1090,7 +1072,7 @@ __ profile_null_seen(x12); // Store a null - do_oop_store(_masm, element_address, noreg, IS_ARRAY); + __ store_heap_oop(element_address, noreg, x28, x29, x13, IS_ARRAY); // Pop stack arguments __ bind(done); @@ -2429,7 +2411,7 @@ __ sub(t0, flags, (u1)atos); __ bnez(t0, notObj); // atos - do_oop_load(_masm, field, x10, IN_HEAP); + __ load_heap_oop(x10, field, x28, x29, IN_HEAP); __ push(atos); if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_agetfield, bc, x11); @@ -2689,7 +2671,7 @@ __ add(off, obj, off); // if static, obj from cache, else obj from stack. const Address field(off, 0); // Store into the field - do_oop_store(_masm, field, x10, IN_HEAP); + __ store_heap_oop(field, x10, x28, x29, x13, IN_HEAP); if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_aputfield, bc, x11, true, byte_no); } @@ -2942,10 +2924,10 @@ __ add(x11, x12, x11); const Address field(x11, 0); - // access field + // access field, must not clobber x13 - flags switch (bytecode()) { case Bytecodes::_fast_aputfield: - do_oop_store(_masm, field, x10, IN_HEAP); + __ store_heap_oop(field, x10, x28, x29, x15, IN_HEAP); break; case Bytecodes::_fast_lputfield: __ access_store_at(T_LONG, IN_HEAP, field, x10, noreg, noreg, noreg); @@ -3033,7 +3015,7 @@ // access field switch (bytecode()) { case Bytecodes::_fast_agetfield: - do_oop_load(_masm, field, x10, IN_HEAP); + __ load_heap_oop(x10, field, x28, x29, IN_HEAP); __ verify_oop(x10); break; case Bytecodes::_fast_lgetfield: @@ -3092,7 +3074,7 @@ break; case atos: __ add(x10, x10, x11); - do_oop_load(_masm, Address(x10, 0), x10, IN_HEAP); + __ load_heap_oop(x10, Address(x10, 0), x28, x29, IN_HEAP); __ verify_oop(x10); break; case ftos: diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -31,11 +31,15 @@ size_t ZPointerLoadShift; size_t ZPlatformAddressOffsetBits() { +#ifdef ADDRESS_SANITIZER + return 44; +#else const size_t min_address_offset_bits = 42; // 4TB const size_t max_address_offset_bits = 44; // 16TB const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); const size_t address_offset_bits = log2i_exact(address_offset); return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); +#endif } size_t ZPlatformAddressHeapBaseShift() { diff -Nru openjdk-21-21.0.8+9/src/hotspot/cpu/x86/macroAssembler_x86.cpp openjdk-21-21.0.9+10/src/hotspot/cpu/x86/macroAssembler_x86.cpp --- openjdk-21-21.0.8+9/src/hotspot/cpu/x86/macroAssembler_x86.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/cpu/x86/macroAssembler_x86.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -3998,7 +3998,7 @@ RegSet regs; #ifdef _LP64 regs += RegSet::of(rax, rcx, rdx); -#ifndef WINDOWS +#ifndef _WINDOWS regs += RegSet::of(rsi, rdi); #endif regs += RegSet::range(r8, r11); @@ -4010,7 +4010,7 @@ XMMRegSet MacroAssembler::call_clobbered_xmm_registers() { int num_xmm_registers = XMMRegister::available_xmm_registers(); -#if defined(WINDOWS) && defined(_LP64) +#if defined(_WINDOWS) && defined(_LP64) XMMRegSet result = XMMRegSet::range(xmm0, xmm5); if (num_xmm_registers > 16) { result += XMMRegSet::range(xmm16, as_XMMRegister(num_xmm_registers - 1)); diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/aix/os_aix.cpp openjdk-21-21.0.9+10/src/hotspot/os/aix/os_aix.cpp --- openjdk-21-21.0.8+9/src/hotspot/os/aix/os_aix.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/aix/os_aix.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -2702,7 +2702,7 @@ dummy, &dummy_size) == 0) { tid = pinfo.__pi_tid; } else { - tty->print_cr("pthread_getthrds_np failed."); + tty->print_cr("pthread_getthrds_np failed, errno: %d.", errno); error = true; } @@ -2713,7 +2713,7 @@ sys_time = thrdentry.ti_ru.ru_stime.tv_sec * 1000000000LL + thrdentry.ti_ru.ru_stime.tv_usec * 1000LL; user_time = thrdentry.ti_ru.ru_utime.tv_sec * 1000000000LL + thrdentry.ti_ru.ru_utime.tv_usec * 1000LL; } else { - tty->print_cr("pthread_getthrds_np failed."); + tty->print_cr("getthrds64 failed, errno: %d.", errno); error = true; } } diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupSubsystem_linux.cpp openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupSubsystem_linux.cpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupSubsystem_linux.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupSubsystem_linux.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -28,6 +28,7 @@ #include "cgroupSubsystem_linux.hpp" #include "cgroupV1Subsystem_linux.hpp" #include "cgroupV2Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "os_linux.hpp" @@ -41,7 +42,7 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupV1MemoryController* memory = nullptr; CgroupV1Controller* cpuset = nullptr; - CgroupV1Controller* cpu = nullptr; + CgroupV1CpuController* cpu = nullptr; CgroupV1Controller* cpuacct = nullptr; CgroupV1Controller* pids = nullptr; CgroupInfo cg_infos[CG_INFO_LENGTH]; @@ -61,12 +62,18 @@ if (is_cgroup_v2(&cg_type_flags)) { // Cgroups v2 case, we have all the info we need. // Construct the subsystem, free resources and return - // Note: any index in cg_infos will do as the path is the same for - // all controllers. - CgroupController* unified = new CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, cg_infos[MEMORY_IDX]._cgroup_path); + // Note: We use the memory for non-cpu non-memory controller look-ups. + // Perhaps we ought to have separate controllers for all. + CgroupV2Controller mem_other = CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, + cg_infos[MEMORY_IDX]._cgroup_path, + cg_infos[MEMORY_IDX]._read_only); + CgroupV2MemoryController* memory = new CgroupV2MemoryController(mem_other); + CgroupV2CpuController* cpu = new CgroupV2CpuController(CgroupV2Controller(cg_infos[CPU_IDX]._mount_path, + cg_infos[CPU_IDX]._cgroup_path, + cg_infos[CPU_IDX]._read_only)); log_debug(os, container)("Detected cgroups v2 unified hierarchy"); cleanup(cg_infos); - return new CgroupV2Subsystem(unified); + return new CgroupV2Subsystem(memory, cpu, mem_other); } /* @@ -100,19 +107,19 @@ CgroupInfo info = cg_infos[i]; if (info._data_complete) { // pids controller might have incomplete data if (strcmp(info._name, "memory") == 0) { - memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path); + memory = new CgroupV1MemoryController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only)); memory->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuset") == 0) { - cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpuset->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpu") == 0) { - cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpu = new CgroupV1CpuController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only)); cpu->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuacct") == 0) { - cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpuacct->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "pids") == 0) { - pids = new CgroupV1Controller(info._root_mount_path, info._mount_path); + pids = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); pids->set_subsystem_path(info._cgroup_path); } } else { @@ -127,7 +134,8 @@ int controller, const char* name, char* mount_path, - char* root_path) { + char* root_path, + bool read_only) { if (cg_infos[controller]._mount_path != nullptr) { // On some systems duplicate controllers get mounted in addition to // the main cgroup controllers most likely under /sys/fs/cgroup. In that @@ -139,6 +147,7 @@ os::free(cg_infos[controller]._root_mount_path); cg_infos[controller]._mount_path = os::strdup(mount_path); cg_infos[controller]._root_mount_path = os::strdup(root_path); + cg_infos[controller]._read_only = read_only; } else { log_debug(os, container)("Duplicate %s controllers detected. Picking %s, skipping %s.", name, cg_infos[controller]._mount_path, mount_path); @@ -146,9 +155,66 @@ } else { cg_infos[controller]._mount_path = os::strdup(mount_path); cg_infos[controller]._root_mount_path = os::strdup(root_path); + cg_infos[controller]._read_only = read_only; } } +/* + * Determine whether or not the mount options, which are comma separated, + * contain the 'ro' string. + */ +static bool find_ro_opt(char* mount_opts) { + char* token; + char* mo_ptr = mount_opts; + // mount options are comma-separated (man proc). + while ((token = strsep(&mo_ptr, ",")) != NULL) { + if (strcmp(token, "ro") == 0) { + return true; + } + } + return false; +} + +/* + * Read values of a /proc/self/mountinfo line into variables. For cgroups v1 + * super options are needed. On cgroups v2 super options are not used. + * + * The scanning of a single mountinfo line entry is as follows: + * + * 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + * (1) (2) (3):(4) (5) (6) (7) (8) (9) (10) (11) (12) + * + * The numbers in parentheses are labels for the descriptions below: + * + * (1) mount ID: matched with '%*d' and discarded + * (2) parent ID: matched with '%*d' and discarded + * (3) major: ---,---> major, minor separated by ':'. matched with '%*d:%*d' and discarded + * (4) minor: ---' + * (5) root: matched with '%s' and captured in 'tmproot'. Must be non-empty. + * (6) mount point: matched with '%s' and captured in 'tmpmount'. Must be non-empty. + * (7) mount options: matched with '%s' and captured in 'mount_opts'. Must be non-empty. + * (8) optional fields: ---,---> matched with '%*[^-]-'. Anything not a hyphen, followed by a hyphen + * (9) separator: ---' and discarded. Note: The discarded match is space characters if there + * are no optionals. Otherwise it includes the optional fields as well. + * (10) filesystem type: matched with '%s' and captured in 'tmp_fs_type' + * (11) mount source: matched with '%*s' and discarded + * (12) super options: matched with '%s' and captured in 'tmpcgroups' + */ +static inline bool match_mount_info_line(char* line, + char* tmproot, + char* tmpmount, + char* mount_opts, + char* tmp_fs_type, + char* tmpcgroups) { + return sscanf(line, + "%*d %*d %*d:%*d %s %s %s%*[^-]- %s %*s %s", + tmproot, + tmpmount, + mount_opts, + tmp_fs_type, + tmpcgroups) == 5; +} + bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, const char* proc_cgroups, const char* proc_self_cgroup, @@ -320,26 +386,40 @@ char tmproot[MAXPATHLEN+1]; char tmpmount[MAXPATHLEN+1]; char tmpcgroups[MAXPATHLEN+1]; + char mount_opts[MAXPATHLEN+1]; char *cptr = tmpcgroups; char *token; - // Cgroup v2 relevant info. We only look for the _mount_path iff is_cgroupsV2 so - // as to avoid memory stomping of the _mount_path pointer later on in the cgroup v1 - // block in the hybrid case. - if (is_cgroupsV2 && sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- %s %*s %*s", tmproot, tmpmount, tmp_fs_type) == 3) { + /* Cgroup v2 relevant info. We only look for the _mount_path iff is_cgroupsV2 so + * as to avoid memory stomping of the _mount_path pointer later on in the cgroup v1 + * block in the hybrid case. + * + * We collect the read only mount option in the cgroup infos so as to have that + * info ready when determining is_containerized(). + */ + if (is_cgroupsV2 && match_mount_info_line(p, + tmproot, + tmpmount, + mount_opts, + tmp_fs_type, + tmpcgroups /* unused */)) { // we likely have an early match return (e.g. cgroup fs match), be sure we have cgroup2 as fstype if (strcmp("cgroup2", tmp_fs_type) == 0) { cgroupv2_mount_point_found = true; any_cgroup_mounts_found = true; + // For unified we only have a single line with cgroup2 fs type. + // Therefore use that option for all CG info structs. + bool ro_option = find_ro_opt(mount_opts); for (int i = 0; i < CG_INFO_LENGTH; i++) { - set_controller_paths(cg_infos, i, "(cg2, unified)", tmpmount, tmproot); + set_controller_paths(cg_infos, i, "(cg2, unified)", tmpmount, tmproot, ro_option); } } } /* Cgroup v1 relevant info * - * Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids + * Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids. For each controller + * determine whether or not they show up as mounted read only or not. * * Example for docker: * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory @@ -348,8 +428,9 @@ * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory * * 44 31 0:39 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,pids + * */ - if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- %s %*s %s", tmproot, tmpmount, tmp_fs_type, tmpcgroups) == 4) { + if (match_mount_info_line(p, tmproot, tmpmount, mount_opts, tmp_fs_type, tmpcgroups)) { if (strcmp("cgroup", tmp_fs_type) != 0) { // Skip cgroup2 fs lines on hybrid or unified hierarchy. continue; @@ -357,23 +438,28 @@ while ((token = strsep(&cptr, ",")) != nullptr) { if (strcmp(token, "memory") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, MEMORY_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, MEMORY_IDX, token, tmpmount, tmproot, ro_option); cg_infos[MEMORY_IDX]._data_complete = true; } else if (strcmp(token, "cpuset") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPUSET_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPUSET_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPUSET_IDX]._data_complete = true; } else if (strcmp(token, "cpu") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPU_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPU_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPU_IDX]._data_complete = true; } else if (strcmp(token, "cpuacct") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPUACCT_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPUACCT_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPUACCT_IDX]._data_complete = true; } else if (strcmp(token, "pids") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, PIDS_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, PIDS_IDX, token, tmpmount, tmproot, ro_option); cg_infos[PIDS_IDX]._data_complete = true; } } @@ -477,13 +563,13 @@ */ int CgroupSubsystem::active_processor_count() { int quota_count = 0; - int cpu_count, limit_count; + int cpu_count; int result; // We use a cache with a timeout to avoid performing expensive // computations in the event this function is called frequently. // [See 8227006]. - CachingCgroupController* contrl = cpu_controller(); + CachingCgroupController* contrl = cpu_controller(); CachedMetric* cpu_limit = contrl->metrics_cache(); if (!cpu_limit->should_check_metric()) { int val = (int)cpu_limit->value(); @@ -491,23 +577,8 @@ return val; } - cpu_count = limit_count = os::Linux::active_processor_count(); - int quota = cpu_quota(); - int period = cpu_period(); - - if (quota > -1 && period > 0) { - quota_count = ceilf((float)quota / (float)period); - log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); - } - - // Use quotas - if (quota_count != 0) { - limit_count = quota_count; - } - - result = MIN2(cpu_count, limit_count); - log_trace(os, container)("OSContainer::active_processor_count: %d", result); - + cpu_count = os::Linux::active_processor_count(); + result = CgroupUtil::processor_count(contrl->controller(), cpu_count); // Update cached metric to avoid re-reading container settings too often cpu_limit->set_value(result, OSCONTAINER_CACHE_TIMEOUT); @@ -524,55 +595,221 @@ * OSCONTAINER_ERROR for not supported */ jlong CgroupSubsystem::memory_limit_in_bytes() { - CachingCgroupController* contrl = memory_controller(); + CachingCgroupController* contrl = memory_controller(); CachedMetric* memory_limit = contrl->metrics_cache(); if (!memory_limit->should_check_metric()) { return memory_limit->value(); } jlong phys_mem = os::Linux::physical_memory(); log_trace(os, container)("total physical memory: " JLONG_FORMAT, phys_mem); - jlong mem_limit = read_memory_limit_in_bytes(); + jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(phys_mem); + // Update cached metric to avoid re-reading container settings too often + memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT); + return mem_limit; +} - if (mem_limit <= 0 || mem_limit >= phys_mem) { - jlong read_mem_limit = mem_limit; - const char *reason; - if (mem_limit >= phys_mem) { - // Exceeding physical memory is treated as unlimited. Cg v1's implementation - // of read_memory_limit_in_bytes() caps this at phys_mem since Cg v1 has no - // value to represent 'max'. Cg v2 may return a value >= phys_mem if e.g. the - // container engine was started with a memory flag exceeding it. - reason = "ignored"; - mem_limit = -1; - } else if (OSCONTAINER_ERROR == mem_limit) { - reason = "failed"; - } else { - assert(mem_limit == -1, "Expected unlimited"); - reason = "unlimited"; +bool CgroupController::read_string(const char* filename, char* buf, size_t buf_size) { + assert(buf != nullptr, "buffer must not be null"); + assert(filename != nullptr, "filename must be given"); + const char* s_path = subsystem_path(); + if (s_path == nullptr) { + log_debug(os, container)("read_string: subsystem path is null"); + return false; + } + + stringStream file_path; + file_path.print_raw(s_path); + file_path.print_raw(filename); + + if (file_path.size() > MAXPATHLEN) { + log_debug(os, container)("File path too long %s, %s", file_path.base(), filename); + return false; + } + const char* absolute_path = file_path.freeze(); + log_trace(os, container)("Path to %s is %s", filename, absolute_path); + + FILE* fp = os::fopen(absolute_path, "r"); + if (fp == nullptr) { + log_debug(os, container)("Open of file %s failed, %s", absolute_path, os::strerror(errno)); + return false; + } + + // Read a single line into the provided buffer. + // At most buf_size - 1 characters. + char* line = fgets(buf, buf_size, fp); + fclose(fp); + if (line == nullptr) { + log_debug(os, container)("Empty file %s", absolute_path); + return false; + } + size_t len = strlen(line); + assert(len <= buf_size - 1, "At most buf_size - 1 bytes can be read"); + if (line[len - 1] == '\n') { + line[len - 1] = '\0'; // trim trailing new line + } + return true; +} + +bool CgroupController::read_number(const char* filename, julong* result) { + char buf[1024]; + bool is_ok = read_string(filename, buf, 1024); + if (!is_ok) { + return false; + } + int matched = sscanf(buf, JULONG_FORMAT, result); + if (matched == 1) { + return true; + } + return false; +} + +bool CgroupController::read_number_handle_max(const char* filename, jlong* result) { + char buf[1024]; + bool is_ok = read_string(filename, buf, 1024); + if (!is_ok) { + return false; + } + jlong val = limit_from_str(buf); + if (val == OSCONTAINER_ERROR) { + return false; + } + *result = val; + return true; +} + +bool CgroupController::read_numerical_key_value(const char* filename, const char* key, julong* result) { + assert(key != nullptr, "key must be given"); + assert(result != nullptr, "result pointer must not be null"); + assert(filename != nullptr, "file to search in must be given"); + const char* s_path = subsystem_path(); + if (s_path == nullptr) { + log_debug(os, container)("read_numerical_key_value: subsystem path is null"); + return false; + } + + stringStream file_path; + file_path.print_raw(s_path); + file_path.print_raw(filename); + + if (file_path.size() > MAXPATHLEN) { + log_debug(os, container)("File path too long %s, %s", file_path.base(), filename); + return false; + } + const char* absolute_path = file_path.freeze(); + log_trace(os, container)("Path to %s is %s", filename, absolute_path); + FILE* fp = os::fopen(absolute_path, "r"); + if (fp == nullptr) { + log_debug(os, container)("Open of file %s failed, %s", absolute_path, os::strerror(errno)); + return false; + } + + const int buf_len = MAXPATHLEN+1; + char buf[buf_len]; + char* line = fgets(buf, buf_len, fp); + bool found_match = false; + // File consists of multiple lines in a "key value" + // fashion, we have to find the key. + const size_t key_len = strlen(key); + for (; line != nullptr; line = fgets(buf, buf_len, fp)) { + char after_key = line[key_len]; + if (strncmp(line, key, key_len) == 0 + && isspace(after_key) != 0 + && after_key != '\n') { + // Skip key, skip space + const char* value_substr = line + key_len + 1; + int matched = sscanf(value_substr, JULONG_FORMAT, result); + found_match = matched == 1; + if (found_match) { + break; + } } - log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, - reason, read_mem_limit, phys_mem); } + fclose(fp); + if (found_match) { + return true; + } + log_debug(os, container)("Type %s (key == %s) not found in file %s", JULONG_FORMAT, + key, absolute_path); + return false; +} - // Update cached metric to avoid re-reading container settings too often - memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT); - return mem_limit; +bool CgroupController::read_numerical_tuple_value(const char* filename, bool use_first, jlong* result) { + char buf[1024]; + bool is_ok = read_string(filename, buf, 1024); + if (!is_ok) { + return false; + } + char token[1024]; + const int matched = sscanf(buf, (use_first ? "%1023s %*s" : "%*s %1023s"), token); + if (matched != 1) { + return false; + } + jlong val = limit_from_str(token); + if (val == OSCONTAINER_ERROR) { + return false; + } + *result = val; + return true; } -jlong CgroupSubsystem::limit_from_str(char* limit_str) { +jlong CgroupController::limit_from_str(char* limit_str) { if (limit_str == nullptr) { return OSCONTAINER_ERROR; } // Unlimited memory in cgroups is the literal string 'max' for // some controllers, for example the pids controller. if (strcmp("max", limit_str) == 0) { - os::free(limit_str); return (jlong)-1; } julong limit; if (sscanf(limit_str, JULONG_FORMAT, &limit) != 1) { - os::free(limit_str); return OSCONTAINER_ERROR; } - os::free(limit_str); return (jlong)limit; } + +// CgroupSubsystem implementations + +jlong CgroupSubsystem::memory_and_swap_limit_in_bytes() { + julong phys_mem = os::Linux::physical_memory(); + julong host_swap = os::Linux::host_swap(); + return memory_controller()->controller()->memory_and_swap_limit_in_bytes(phys_mem, host_swap); +} + +jlong CgroupSubsystem::memory_soft_limit_in_bytes() { + julong phys_mem = os::Linux::physical_memory(); + return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem); +} + +jlong CgroupSubsystem::memory_usage_in_bytes() { + return memory_controller()->controller()->memory_usage_in_bytes(); +} + +jlong CgroupSubsystem::memory_max_usage_in_bytes() { + return memory_controller()->controller()->memory_max_usage_in_bytes(); +} + +jlong CgroupSubsystem::rss_usage_in_bytes() { + return memory_controller()->controller()->rss_usage_in_bytes(); +} + +jlong CgroupSubsystem::cache_usage_in_bytes() { + return memory_controller()->controller()->cache_usage_in_bytes(); +} + +int CgroupSubsystem::cpu_quota() { + return cpu_controller()->controller()->cpu_quota(); +} + +int CgroupSubsystem::cpu_period() { + return cpu_controller()->controller()->cpu_period(); +} + +int CgroupSubsystem::cpu_shares() { + return cpu_controller()->controller()->cpu_shares(); +} + +void CgroupSubsystem::print_version_specific_info(outputStream* st) { + julong phys_mem = os::Linux::physical_memory(); + memory_controller()->controller()->print_version_specific_info(st, phys_mem); +} diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupSubsystem_linux.hpp openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupSubsystem_linux.hpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupSubsystem_linux.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupSubsystem_linux.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -69,148 +69,98 @@ #define MEMORY_IDX 3 #define PIDS_IDX 4 -typedef char * cptr; - -class CgroupController: public CHeapObj { - public: - virtual char *subsystem_path() = 0; -}; - -PRAGMA_DIAG_PUSH -PRAGMA_FORMAT_NONLITERAL_IGNORED -// Parses a subsystem's file, looking for a matching line. -// If key is null, then the first line will be matched with scan_fmt. -// If key isn't null, then each line will be matched, looking for something that matches "$key $scan_fmt". -// The matching value will be assigned to returnval. -// scan_fmt uses scanf() syntax. -// Return value: 0 on match, OSCONTAINER_ERROR on error. -template int subsystem_file_line_contents(CgroupController* c, - const char *filename, - const char *key, - const char *scan_fmt, - T returnval) { - if (c == nullptr) { - log_debug(os, container)("subsystem_file_line_contents: CgroupController* is null"); - return OSCONTAINER_ERROR; - } - if (c->subsystem_path() == nullptr) { - log_debug(os, container)("subsystem_file_line_contents: subsystem path is null"); - return OSCONTAINER_ERROR; - } - - stringStream file_path; - file_path.print_raw(c->subsystem_path()); - file_path.print_raw(filename); - - if (file_path.size() > (MAXPATHLEN-1)) { - log_debug(os, container)("File path too long %s, %s", file_path.base(), filename); - return OSCONTAINER_ERROR; - } - const char* absolute_path = file_path.freeze(); - log_trace(os, container)("Path to %s is %s", filename, absolute_path); - - FILE* fp = os::fopen(absolute_path, "r"); - if (fp == nullptr) { - log_debug(os, container)("Open of file %s failed, %s", absolute_path, os::strerror(errno)); - return OSCONTAINER_ERROR; - } - - const int buf_len = MAXPATHLEN+1; - char buf[buf_len]; - char* line = fgets(buf, buf_len, fp); - if (line == nullptr) { - log_debug(os, container)("Empty file %s", absolute_path); - fclose(fp); - return OSCONTAINER_ERROR; - } - - bool found_match = false; - if (key == nullptr) { - // File consists of a single line according to caller, with only a value - int matched = sscanf(line, scan_fmt, returnval); - found_match = matched == 1; - } else { - // File consists of multiple lines in a "key value" - // fashion, we have to find the key. - const int key_len = (int)strlen(key); - for (; line != nullptr; line = fgets(buf, buf_len, fp)) { - char* key_substr = strstr(line, key); - char after_key = line[key_len]; - if (key_substr == line - && isspace(after_key) != 0 - && after_key != '\n') { - // Skip key, skip space - const char* value_substr = line + key_len + 1; - int matched = sscanf(value_substr, scan_fmt, returnval); - found_match = matched == 1; - if (found_match) { - break; - } - } - } - } - fclose(fp); - if (found_match) { - return 0; - } - log_debug(os, container)("Type %s (key == %s) not found in file %s", scan_fmt, - (key == nullptr ? "null" : key), absolute_path); - return OSCONTAINER_ERROR; +#define CONTAINER_READ_NUMBER_CHECKED(controller, filename, log_string, retval) \ +{ \ + bool is_ok; \ + is_ok = controller->read_number(filename, &retval); \ + if (!is_ok) { \ + log_trace(os, container)(log_string " failed: %d", OSCONTAINER_ERROR); \ + return OSCONTAINER_ERROR; \ + } \ + log_trace(os, container)(log_string " is: " JULONG_FORMAT, retval); \ } -PRAGMA_DIAG_POP -// log_fmt can be different than scan_fmt. For example -// cpu_period() for cgv2 uses log_fmt='%d' and scan_fmt='%*s %d' -#define GET_CONTAINER_INFO(return_type, subsystem, filename, \ - logstring, log_fmt, scan_fmt, variable) \ - return_type variable; \ -{ \ - int err; \ - err = subsystem_file_line_contents(subsystem, \ - filename, \ - nullptr, \ - scan_fmt, \ - &variable); \ - if (err != 0) { \ - log_trace(os, container)(logstring "%d", OSCONTAINER_ERROR); \ - return (return_type) OSCONTAINER_ERROR; \ - } \ - \ - log_trace(os, container)(logstring log_fmt, variable); \ +#define CONTAINER_READ_NUMBER_CHECKED_MAX(controller, filename, log_string, retval) \ +{ \ + bool is_ok; \ + is_ok = controller->read_number_handle_max(filename, &retval); \ + if (!is_ok) { \ + log_trace(os, container)(log_string " failed: %d", OSCONTAINER_ERROR); \ + return OSCONTAINER_ERROR; \ + } \ + log_trace(os, container)(log_string " is: " JLONG_FORMAT, retval); \ } -#define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \ - logstring, scan_fmt, variable, bufsize) \ - char variable[bufsize]; \ -{ \ - int err; \ - err = subsystem_file_line_contents(subsystem, \ - filename, \ - nullptr, \ - scan_fmt, \ - variable); \ - if (err != 0) \ - return (return_type) nullptr; \ - \ - log_trace(os, container)(logstring, variable); \ +#define CONTAINER_READ_STRING_CHECKED(controller, filename, log_string, retval, buf_size) \ +{ \ + bool is_ok; \ + is_ok = controller->read_string(filename, retval, buf_size); \ + if (!is_ok) { \ + log_trace(os, container)(log_string " failed: %d", OSCONTAINER_ERROR); \ + return nullptr; \ + } \ + log_trace(os, container)(log_string " is: %s", retval); \ } -#define GET_CONTAINER_INFO_LINE(return_type, controller, filename, \ - matchline, logstring, scan_fmt, variable) \ - return_type variable; \ -{ \ - int err; \ - err = subsystem_file_line_contents(controller, \ - filename, \ - matchline, \ - scan_fmt, \ - &variable); \ - if (err != 0) \ - return (return_type) OSCONTAINER_ERROR; \ - \ - log_trace(os, container)(logstring, variable); \ -} +class CgroupController: public CHeapObj { + protected: + char* _cgroup_path; + char* _mount_point; + public: + virtual const char* subsystem_path() = 0; + virtual bool is_read_only() = 0; + const char* cgroup_path() { return _cgroup_path; } + const char* mount_point() { return _mount_point; } + virtual bool needs_hierarchy_adjustment() { return false; } + + /* Read a numerical value as unsigned long + * + * returns: false if any error occurred. true otherwise and + * the parsed value is set in the provided julong pointer. + */ + bool read_number(const char* filename, julong* result); + + /* Convenience method to deal with numbers as well as the string 'max' + * in interface files. Otherwise same as read_number(). + * + * returns: false if any error occurred. true otherwise and + * the parsed value (which might be negative) is being set in + * the provided jlong pointer. + */ + bool read_number_handle_max(const char* filename, jlong* result); + + /* Read a string of at most buf_size - 1 characters from the interface file. + * The provided buffer must be at least buf_size in size so as to account + * for the null terminating character. Callers must ensure that the buffer + * is appropriately in-scope and of sufficient size. + * + * returns: false if any error occured. true otherwise and the passed + * in buffer will contain the first buf_size - 1 characters of the string + * or up to the first new line character ('\n') whichever comes first. + */ + bool read_string(const char* filename, char* buf, size_t buf_size); + + /* Read a tuple value as a number. Tuple is: ' '. + * Handles 'max' (for unlimited) for any tuple value. This is handy for + * parsing interface files like cpu.max which contain such tuples. + * + * returns: false if any error occurred. true otherwise and the parsed + * value of the appropriate tuple entry set in the provided jlong pointer. + */ + bool read_numerical_tuple_value(const char* filename, bool use_first, jlong* result); + + /* Read a numerical value from a multi-line interface file. The matched line is + * determined by the provided 'key'. The associated numerical value is being set + * via the passed in julong pointer. Example interface file 'memory.stat' + * + * returns: false if any error occurred. true otherwise and the parsed value is + * being set in the provided julong pointer. + */ + bool read_numerical_key_value(const char* filename, const char* key, julong* result); + private: + static jlong limit_from_str(char* limit_str); +}; class CachedMetric : public CHeapObj{ private: @@ -236,45 +186,81 @@ } }; +template class CachingCgroupController : public CHeapObj { private: - CgroupController* _controller; + T* _controller; CachedMetric* _metrics_cache; public: - CachingCgroupController(CgroupController* cont) { + CachingCgroupController(T* cont) { _controller = cont; _metrics_cache = new CachedMetric(); } CachedMetric* metrics_cache() { return _metrics_cache; } - CgroupController* controller() { return _controller; } + T* controller() { return _controller; } +}; + +// Pure virtual class representing version agnostic CPU controllers +class CgroupCpuController: public CHeapObj { + public: + virtual int cpu_quota() = 0; + virtual int cpu_period() = 0; + virtual int cpu_shares() = 0; + virtual bool needs_hierarchy_adjustment() = 0; + virtual bool is_read_only() = 0; + virtual const char* subsystem_path() = 0; + virtual void set_subsystem_path(const char* cgroup_path) = 0; + virtual const char* mount_point() = 0; + virtual const char* cgroup_path() = 0; +}; + +// Pure virtual class representing version agnostic memory controllers +class CgroupMemoryController: public CHeapObj { + public: + virtual jlong read_memory_limit_in_bytes(julong upper_bound) = 0; + virtual jlong memory_usage_in_bytes() = 0; + virtual jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) = 0; + virtual jlong memory_soft_limit_in_bytes(julong upper_bound) = 0; + virtual jlong memory_max_usage_in_bytes() = 0; + virtual jlong rss_usage_in_bytes() = 0; + virtual jlong cache_usage_in_bytes() = 0; + virtual void print_version_specific_info(outputStream* st, julong host_mem) = 0; + virtual bool needs_hierarchy_adjustment() = 0; + virtual bool is_read_only() = 0; + virtual const char* subsystem_path() = 0; + virtual void set_subsystem_path(const char* cgroup_path) = 0; + virtual const char* mount_point() = 0; + virtual const char* cgroup_path() = 0; }; class CgroupSubsystem: public CHeapObj { public: jlong memory_limit_in_bytes(); int active_processor_count(); - jlong limit_from_str(char* limit_str); - virtual int cpu_quota() = 0; - virtual int cpu_period() = 0; - virtual int cpu_shares() = 0; virtual jlong pids_max() = 0; virtual jlong pids_current() = 0; - virtual jlong memory_usage_in_bytes() = 0; - virtual jlong memory_and_swap_limit_in_bytes() = 0; - virtual jlong memory_soft_limit_in_bytes() = 0; - virtual jlong memory_max_usage_in_bytes() = 0; + virtual bool is_containerized() = 0; virtual char * cpu_cpuset_cpus() = 0; virtual char * cpu_cpuset_memory_nodes() = 0; - virtual jlong read_memory_limit_in_bytes() = 0; virtual const char * container_type() = 0; - virtual CachingCgroupController* memory_controller() = 0; - virtual CachingCgroupController* cpu_controller() = 0; + virtual CachingCgroupController* memory_controller() = 0; + virtual CachingCgroupController* cpu_controller() = 0; - virtual void print_version_specific_info(outputStream* st) = 0; + int cpu_quota(); + int cpu_period(); + int cpu_shares(); + + jlong memory_usage_in_bytes(); + jlong memory_and_swap_limit_in_bytes(); + jlong memory_soft_limit_in_bytes(); + jlong memory_max_usage_in_bytes(); + jlong rss_usage_in_bytes(); + jlong cache_usage_in_bytes(); + void print_version_specific_info(outputStream* st); }; // Utility class for storing info retrieved from /proc/cgroups, @@ -288,6 +274,7 @@ char* _name; int _hierarchy_id; bool _enabled; + bool _read_only; // whether or not the mount path is mounted read-only bool _data_complete; // indicating cgroup v1 data is complete for this controller char* _cgroup_path; // cgroup controller path from /proc/self/cgroup char* _root_mount_path; // root mount path from /proc/self/mountinfo. Unused for cgroup v2 @@ -298,6 +285,7 @@ _name = nullptr; _hierarchy_id = -1; _enabled = false; + _read_only = false; _data_complete = false; _cgroup_path = nullptr; _root_mount_path = nullptr; @@ -329,7 +317,8 @@ int controller, const char* name, char* mount_path, - char* root_path); + char* root_path, + bool read_only); // Determine the cgroup type (version 1 or version 2), given // relevant paths to files. Sets 'flags' accordingly. static bool determine_type(CgroupInfo* cg_infos, diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupUtil_linux.cpp openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupUtil_linux.cpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupUtil_linux.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupUtil_linux.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * 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. + * + */ + +#include "os_linux.hpp" +#include "cgroupUtil_linux.hpp" + +int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { + assert(host_cpus > 0, "physical host cpus must be positive"); + int limit_count = host_cpus; + int quota = cpu_ctrl->cpu_quota(); + int period = cpu_ctrl->cpu_period(); + int quota_count = 0; + int result = 0; + + if (quota > -1 && period > 0) { + quota_count = ceilf((float)quota / (float)period); + log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); + } + + // Use quotas + if (quota_count != 0) { + limit_count = quota_count; + } + + result = MIN2(host_cpus, limit_count); + log_trace(os, container)("OSContainer::active_processor_count: %d", result); + return result; +} + +void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { + if (!mem->needs_hierarchy_adjustment()) { + // nothing to do + return; + } + log_trace(os, container)("Adjusting controller path for memory: %s", mem->subsystem_path()); + assert(mem->cgroup_path() != nullptr, "invariant"); + char* orig = os::strdup(mem->cgroup_path()); + char* cg_path = os::strdup(orig); + char* last_slash; + assert(cg_path[0] == '/', "cgroup path must start with '/'"); + julong phys_mem = os::Linux::physical_memory(); + char* limit_cg_path = nullptr; + jlong limit = mem->read_memory_limit_in_bytes(phys_mem); + jlong lowest_limit = phys_mem; + while ((last_slash = strrchr(cg_path, '/')) != cg_path) { + *last_slash = '\0'; // strip path + // update to shortened path and try again + mem->set_subsystem_path(cg_path); + limit = mem->read_memory_limit_in_bytes(phys_mem); + if (limit >= 0 && limit < lowest_limit) { + lowest_limit = limit; + os::free(limit_cg_path); // handles nullptr + limit_cg_path = os::strdup(cg_path); + } + } + // need to check limit at mount point + mem->set_subsystem_path("/"); + limit = mem->read_memory_limit_in_bytes(phys_mem); + if (limit >= 0 && limit < lowest_limit) { + lowest_limit = limit; + os::free(limit_cg_path); // handles nullptr + limit_cg_path = os::strdup("/"); + } + assert(lowest_limit >= 0, "limit must be positive"); + if ((julong)lowest_limit != phys_mem) { + // we've found a lower limit anywhere in the hierarchy, + // set the path to the limit path + assert(limit_cg_path != nullptr, "limit path must be set"); + mem->set_subsystem_path(limit_cg_path); + log_trace(os, container)("Adjusted controller path for memory to: %s. " + "Lowest limit was: " JLONG_FORMAT, + mem->subsystem_path(), + lowest_limit); + } else { + log_trace(os, container)("No lower limit found for memory in hierarchy %s, " + "adjusting to original path %s", + mem->mount_point(), orig); + mem->set_subsystem_path(orig); + } + os::free(cg_path); + os::free(orig); + os::free(limit_cg_path); +} + +void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { + if (!cpu->needs_hierarchy_adjustment()) { + // nothing to do + return; + } + log_trace(os, container)("Adjusting controller path for cpu: %s", cpu->subsystem_path()); + assert(cpu->cgroup_path() != nullptr, "invariant"); + char* orig = os::strdup(cpu->cgroup_path()); + char* cg_path = os::strdup(orig); + char* last_slash; + assert(cg_path[0] == '/', "cgroup path must start with '/'"); + int host_cpus = os::Linux::active_processor_count(); + int cpus = CgroupUtil::processor_count(cpu, host_cpus); + int lowest_limit = host_cpus; + char* limit_cg_path = nullptr; + while ((last_slash = strrchr(cg_path, '/')) != cg_path) { + *last_slash = '\0'; // strip path + // update to shortened path and try again + cpu->set_subsystem_path(cg_path); + cpus = CgroupUtil::processor_count(cpu, host_cpus); + if (cpus != host_cpus && cpus < lowest_limit) { + lowest_limit = cpus; + os::free(limit_cg_path); // handles nullptr + limit_cg_path = os::strdup(cg_path); + } + } + // need to check limit at mount point + cpu->set_subsystem_path("/"); + cpus = CgroupUtil::processor_count(cpu, host_cpus); + if (cpus != host_cpus && cpus < lowest_limit) { + lowest_limit = cpus; + os::free(limit_cg_path); // handles nullptr + limit_cg_path = os::strdup(cg_path); + } + assert(lowest_limit >= 0, "limit must be positive"); + if (lowest_limit != host_cpus) { + // we've found a lower limit anywhere in the hierarchy, + // set the path to the limit path + assert(limit_cg_path != nullptr, "limit path must be set"); + cpu->set_subsystem_path(limit_cg_path); + log_trace(os, container)("Adjusted controller path for cpu to: %s. " + "Lowest limit was: %d", + cpu->subsystem_path(), + lowest_limit); + } else { + log_trace(os, container)("No lower limit found for cpu in hierarchy %s, " + "adjusting to original path %s", + cpu->mount_point(), orig); + cpu->set_subsystem_path(orig); + } + os::free(cg_path); + os::free(orig); + os::free(limit_cg_path); +} diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupUtil_linux.hpp openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupUtil_linux.hpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupUtil_linux.hpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupUtil_linux.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * 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. + * + */ + +#ifndef CGROUP_UTIL_LINUX_HPP +#define CGROUP_UTIL_LINUX_HPP + +#include "utilities/globalDefinitions.hpp" +#include "cgroupSubsystem_linux.hpp" + +class CgroupUtil: AllStatic { + + public: + static int processor_count(CgroupCpuController* cpu, int host_cpus); + // Given a memory controller, adjust its path to a point in the hierarchy + // that represents the closest memory limit. + static void adjust_controller(CgroupMemoryController* m); + // Given a cpu controller, adjust its path to a point in the hierarchy + // that represents the closest cpu limit. + static void adjust_controller(CgroupCpuController* c); +}; + +#endif // CGROUP_UTIL_LINUX_HPP diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -26,6 +26,7 @@ #include #include #include "cgroupV1Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "runtime/globals.hpp" @@ -37,7 +38,15 @@ * Set directory to subsystem specific files based * on the contents of the mountinfo and cgroup files. */ -void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { +void CgroupV1Controller::set_subsystem_path(const char* cgroup_path) { + if (_cgroup_path != nullptr) { + os::free(_cgroup_path); + } + if (_path != nullptr) { + os::free(_path); + _path = nullptr; + } + _cgroup_path = os::strdup(cgroup_path); stringStream ss; if (_root != nullptr && cgroup_path != nullptr) { if (strcmp(_root, "/") == 0) { @@ -51,7 +60,7 @@ ss.print_raw(_mount_point); _path = os::strdup(ss.base()); } else { - char *p = strstr(cgroup_path, _root); + char *p = strstr((char*)cgroup_path, _root); if (p != nullptr && p == _root) { if (strlen(cgroup_path) > strlen(_root)) { ss.print_raw(_mount_point); @@ -65,48 +74,47 @@ } } -/* uses_mem_hierarchy - * - * Return whether or not hierarchical cgroup accounting is being - * done. - * - * return: - * A number > 0 if true, or - * OSCONTAINER_ERROR for not supported +/* + * The common case, containers, we have _root == _cgroup_path, and thus set the + * controller path to the _mount_point. This is where the limits are exposed in + * the cgroup pseudo filesystem (at the leaf) and adjustment of the path won't + * be needed for that reason. */ -jlong CgroupV1MemoryController::uses_mem_hierarchy() { - GET_CONTAINER_INFO(jlong, this, "/memory.use_hierarchy", - "Use Hierarchy is: ", JLONG_FORMAT, JLONG_FORMAT, use_hierarchy); - return use_hierarchy; -} - -void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) { - CgroupV1Controller::set_subsystem_path(cgroup_path); - jlong hierarchy = uses_mem_hierarchy(); - if (hierarchy > 0) { - set_hierarchical(true); - } +bool CgroupV1Controller::needs_hierarchy_adjustment() { + assert(_cgroup_path != nullptr, "sanity"); + return strcmp(_root, _cgroup_path) != 0; } -jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.limit_in_bytes", - "Memory Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memlimit); - - if (memlimit >= os::Linux::physical_memory()) { - log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); - CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller()); - if (mem_controller->is_hierarchical()) { - GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", "hierarchical_memory_limit", - "Hierarchical Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, hier_memlimit) - if (hier_memlimit >= os::Linux::physical_memory()) { - log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); +static inline +void verbose_log(julong read_mem_limit, julong host_mem) { + if (log_is_enabled(Debug, os, container)) { + jlong mem_limit = (jlong)read_mem_limit; // account for negative values + if (mem_limit < 0 || read_mem_limit >= host_mem) { + const char *reason; + if (mem_limit == OSCONTAINER_ERROR) { + reason = "failed"; + } else if (mem_limit == -1) { + reason = "unlimited"; } else { - return (jlong)hier_memlimit; + assert(read_mem_limit >= host_mem, "Expected read value exceeding host_mem"); + // Exceeding physical memory is treated as unlimited. This implementation + // caps it at host_mem since Cg v1 has no value to represent 'max'. + reason = "ignored"; } + log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, + reason, mem_limit, host_mem); } - return (jlong)-1; } - else { +} + +jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) { + julong memlimit; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.limit_in_bytes", "Memory Limit", memlimit); + if (memlimit >= phys_mem) { + verbose_log(memlimit, phys_mem); + return (jlong)-1; + } else { + verbose_log(memlimit, phys_mem); return (jlong)memlimit; } } @@ -123,32 +131,19 @@ * * -1 if there isn't any limit in place (note: includes values which exceed a physical * upper bound) */ -jlong CgroupV1Subsystem::read_mem_swap() { - julong host_total_memsw; - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.memsw.limit_in_bytes", - "Memory and Swap Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memswlimit); - host_total_memsw = os::Linux::host_swap() + os::Linux::physical_memory(); +jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) { + julong memswlimit; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit); if (memswlimit >= host_total_memsw) { - log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); - CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller()); - if (mem_controller->is_hierarchical()) { - const char* matchline = "hierarchical_memsw_limit"; - GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchline, - "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, JULONG_FORMAT, hier_memswlimit) - if (hier_memswlimit >= host_total_memsw) { - log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited"); - } else { - return (jlong)hier_memswlimit; - } - } + log_trace(os, container)("Memory and Swap Limit is: Unlimited"); return (jlong)-1; } else { return (jlong)memswlimit; } } -jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { - jlong memory_swap = read_mem_swap(); +jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) { + jlong memory_swap = read_mem_swap(host_mem + host_swap); if (memory_swap == -1) { return memory_swap; } @@ -157,7 +152,7 @@ // supported. jlong swappiness = read_mem_swappiness(); if (swappiness == 0 || memory_swap == OSCONTAINER_ERROR) { - jlong memlimit = read_memory_limit_in_bytes(); + jlong memlimit = read_memory_limit_in_bytes(host_mem); if (memory_swap == OSCONTAINER_ERROR) { log_trace(os, container)("Memory and Swap Limit has been reset to " JLONG_FORMAT " because swap is not supported", memlimit); } else { @@ -168,16 +163,23 @@ return memory_swap; } -jlong CgroupV1Subsystem::read_mem_swappiness() { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.swappiness", - "Swappiness is: ", JULONG_FORMAT, JULONG_FORMAT, swappiness); - return swappiness; -} - -jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.soft_limit_in_bytes", - "Memory Soft Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memsoftlimit); - if (memsoftlimit >= os::Linux::physical_memory()) { +static inline +jlong memory_swap_usage_impl(CgroupController* ctrl) { + julong memory_swap_usage; + CONTAINER_READ_NUMBER_CHECKED(ctrl, "/memory.memsw.usage_in_bytes", "mem swap usage", memory_swap_usage); + return (jlong)memory_swap_usage; +} + +jlong CgroupV1MemoryController::read_mem_swappiness() { + julong swappiness; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.swappiness", "Swappiness", swappiness); + return (jlong)swappiness; +} + +jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { + julong memsoftlimit; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.soft_limit_in_bytes", "Memory Soft Limit", memsoftlimit); + if (memsoftlimit >= phys_mem) { log_trace(os, container)("Memory Soft Limit is: Unlimited"); return (jlong)-1; } else { @@ -185,6 +187,32 @@ } } +// Constructor +CgroupV1Subsystem::CgroupV1Subsystem(CgroupV1Controller* cpuset, + CgroupV1CpuController* cpu, + CgroupV1Controller* cpuacct, + CgroupV1Controller* pids, + CgroupV1MemoryController* memory) : + _cpuset(cpuset), + _cpuacct(cpuacct), + _pids(pids) { + CgroupUtil::adjust_controller(memory); + CgroupUtil::adjust_controller(cpu); + _memory = new CachingCgroupController(memory); + _cpu = new CachingCgroupController(cpu); +} + +bool CgroupV1Subsystem::is_containerized() { + // containerized iff all required controllers are mounted + // read-only. See OSContainer::is_containerized() for + // the full logic. + // + return _memory->controller()->is_read_only() && + _cpu->controller()->is_read_only() && + _cpuacct->is_read_only() && + _cpuset->is_read_only(); +} + /* memory_usage_in_bytes * * Return the amount of used memory for this process. @@ -194,10 +222,10 @@ * -1 for unlimited * OSCONTAINER_ERROR for not supported */ -jlong CgroupV1Subsystem::memory_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.usage_in_bytes", - "Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memusage); - return memusage; +jlong CgroupV1MemoryController::memory_usage_in_bytes() { + julong memusage; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.usage_in_bytes", "Memory Usage", memusage); + return (jlong)memusage; } /* memory_max_usage_in_bytes @@ -208,37 +236,60 @@ * max memory usage in bytes or * OSCONTAINER_ERROR for not supported */ -jlong CgroupV1Subsystem::memory_max_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.max_usage_in_bytes", - "Maximum Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memmaxusage); - return memmaxusage; +jlong CgroupV1MemoryController::memory_max_usage_in_bytes() { + julong memmaxusage; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.max_usage_in_bytes", "Maximum Memory Usage", memmaxusage); + return (jlong)memmaxusage; +} + +jlong CgroupV1MemoryController::rss_usage_in_bytes() { + julong rss; + bool is_ok = reader()->read_numerical_key_value("/memory.stat", + "rss", + &rss); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("RSS usage is: " JULONG_FORMAT, rss); + return (jlong)rss; } +jlong CgroupV1MemoryController::cache_usage_in_bytes() { + julong cache; + bool is_ok = reader()->read_numerical_key_value("/memory.stat", + "cache", + &cache); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("Cache usage is: " JULONG_FORMAT, cache); + return (jlong)cache; +} -jlong CgroupV1Subsystem::kernel_memory_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.kmem.usage_in_bytes", - "Kernel Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, kmem_usage); - return kmem_usage; +jlong CgroupV1MemoryController::kernel_memory_usage_in_bytes() { + julong kmem_usage; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.usage_in_bytes", "Kernel Memory Usage", kmem_usage); + return (jlong)kmem_usage; } -jlong CgroupV1Subsystem::kernel_memory_limit_in_bytes() { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.kmem.limit_in_bytes", - "Kernel Memory Limit is: ", JULONG_FORMAT, JULONG_FORMAT, kmem_limit); - if (kmem_limit >= os::Linux::physical_memory()) { +jlong CgroupV1MemoryController::kernel_memory_limit_in_bytes(julong phys_mem) { + julong kmem_limit; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.limit_in_bytes", "Kernel Memory Limit", kmem_limit); + if (kmem_limit >= phys_mem) { return (jlong)-1; } return (jlong)kmem_limit; } -jlong CgroupV1Subsystem::kernel_memory_max_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.kmem.max_usage_in_bytes", - "Maximum Kernel Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, kmem_max_usage); - return kmem_max_usage; +jlong CgroupV1MemoryController::kernel_memory_max_usage_in_bytes() { + julong kmem_max_usage; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.max_usage_in_bytes", "Maximum Kernel Memory Usage", kmem_max_usage); + return (jlong)kmem_max_usage; } -void CgroupV1Subsystem::print_version_specific_info(outputStream* st) { +void CgroupV1MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { jlong kmem_usage = kernel_memory_usage_in_bytes(); - jlong kmem_limit = kernel_memory_limit_in_bytes(); + jlong kmem_limit = kernel_memory_limit_in_bytes(phys_mem); jlong kmem_max_usage = kernel_memory_max_usage_in_bytes(); OSContainer::print_container_helper(st, kmem_limit, "kernel_memory_limit_in_bytes"); @@ -246,15 +297,15 @@ OSContainer::print_container_helper(st, kmem_max_usage, "kernel_memory_max_usage_in_bytes"); } -char * CgroupV1Subsystem::cpu_cpuset_cpus() { - GET_CONTAINER_INFO_CPTR(cptr, _cpuset, "/cpuset.cpus", - "cpuset.cpus is: %s", "%1023s", cpus, 1024); +char* CgroupV1Subsystem::cpu_cpuset_cpus() { + char cpus[1024]; + CONTAINER_READ_STRING_CHECKED(_cpuset, "/cpuset.cpus", "cpuset.cpus", cpus, 1024); return os::strdup(cpus); } -char * CgroupV1Subsystem::cpu_cpuset_memory_nodes() { - GET_CONTAINER_INFO_CPTR(cptr, _cpuset, "/cpuset.mems", - "cpuset.mems is: %s", "%1023s", mems, 1024); +char* CgroupV1Subsystem::cpu_cpuset_memory_nodes() { + char mems[1024]; + CONTAINER_READ_STRING_CHECKED(_cpuset, "/cpuset.mems", "cpuset.mems", mems, 1024); return os::strdup(mems); } @@ -268,16 +319,24 @@ * -1 for no quota * OSCONTAINER_ERROR for not supported */ -int CgroupV1Subsystem::cpu_quota() { - GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.cfs_quota_us", - "CPU Quota is: ", "%d", "%d", quota); - return quota; +int CgroupV1CpuController::cpu_quota() { + julong quota; + bool is_ok = reader()->read_number("/cpu.cfs_quota_us", "a); + if (!is_ok) { + log_trace(os, container)("CPU Quota failed: %d", OSCONTAINER_ERROR); + return OSCONTAINER_ERROR; + } + // cast to int since the read value might be negative + // and we want to avoid logging -1 as a large unsigned value. + int quota_int = (int)quota; + log_trace(os, container)("CPU Quota is: %d", quota_int); + return quota_int; } -int CgroupV1Subsystem::cpu_period() { - GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.cfs_period_us", - "CPU Period is: ", "%d", "%d", period); - return period; +int CgroupV1CpuController::cpu_period() { + julong period; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.cfs_period_us", "CPU Period", period); + return (int)period; } /* cpu_shares @@ -290,20 +349,14 @@ * -1 for no share setup * OSCONTAINER_ERROR for not supported */ -int CgroupV1Subsystem::cpu_shares() { - GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.shares", - "CPU Shares is: ", "%d", "%d", shares); +int CgroupV1CpuController::cpu_shares() { + julong shares; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.shares", "CPU Shares", shares); + int shares_int = (int)shares; // Convert 1024 to no shares setup - if (shares == 1024) return -1; - - return shares; -} - + if (shares_int == 1024) return -1; -char* CgroupV1Subsystem::pids_max_val() { - GET_CONTAINER_INFO_CPTR(cptr, _pids, "/pids.max", - "Maximum number of tasks is: %s", "%1023s", pidsmax, 1024); - return os::strdup(pidsmax); + return shares_int; } /* pids_max @@ -317,8 +370,9 @@ */ jlong CgroupV1Subsystem::pids_max() { if (_pids == nullptr) return OSCONTAINER_ERROR; - char * pidsmax_str = pids_max_val(); - return limit_from_str(pidsmax_str); + jlong pids_max; + CONTAINER_READ_NUMBER_CHECKED_MAX(_pids, "/pids.max", "Maximum number of tasks", pids_max); + return pids_max; } /* pids_current @@ -331,7 +385,7 @@ */ jlong CgroupV1Subsystem::pids_current() { if (_pids == nullptr) return OSCONTAINER_ERROR; - GET_CONTAINER_INFO(jlong, _pids, "/pids.current", - "Current number of tasks is: ", JLONG_FORMAT, JLONG_FORMAT, pids_current); - return pids_current; + julong pids_current; + CONTAINER_READ_NUMBER_CHECKED(_pids, "/pids.current", "Current number of tasks", pids_current); + return (jlong)pids_current; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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,57 +28,125 @@ #include "runtime/os.hpp" #include "memory/allocation.hpp" #include "cgroupSubsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" // Cgroups version 1 specific implementation class CgroupV1Controller: public CgroupController { private: /* mountinfo contents */ - char *_root; - char *_mount_point; + char* _root; + bool _read_only; /* Constructed subsystem directory */ - char *_path; + char* _path; public: - CgroupV1Controller(char *root, char *mountpoint) { - _root = os::strdup(root); + CgroupV1Controller(char *root, + char *mountpoint, + bool ro) : _root(os::strdup(root)), + _read_only(ro), + _path(nullptr) { + _cgroup_path = nullptr; _mount_point = os::strdup(mountpoint); - _path = nullptr; + } + // Shallow copy constructor + CgroupV1Controller(const CgroupV1Controller& o) : _root(o._root), + _read_only(o._read_only), + _path(o._path) { + _cgroup_path = o._cgroup_path; + _mount_point = o._mount_point; + } + ~CgroupV1Controller() { + // At least one subsystem controller exists with paths to malloc'd path + // names } - virtual void set_subsystem_path(char *cgroup_path); - char *subsystem_path() { return _path; } + void set_subsystem_path(const char *cgroup_path); + const char* subsystem_path() override { return _path; } + bool is_read_only() override { return _read_only; } + bool needs_hierarchy_adjustment() override; }; -class CgroupV1MemoryController: public CgroupV1Controller { +class CgroupV1MemoryController final : public CgroupMemoryController { + private: + CgroupV1Controller _reader; + CgroupV1Controller* reader() { return &_reader; } public: - bool is_hierarchical() { return _uses_mem_hierarchy; } - void set_subsystem_path(char *cgroup_path); + void set_subsystem_path(const char *cgroup_path) override { + reader()->set_subsystem_path(cgroup_path); + } + jlong read_memory_limit_in_bytes(julong upper_bound) override; + jlong memory_usage_in_bytes() override; + jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override; + jlong memory_soft_limit_in_bytes(julong upper_bound) override; + jlong memory_max_usage_in_bytes() override; + jlong rss_usage_in_bytes() override; + jlong cache_usage_in_bytes() override; + jlong kernel_memory_usage_in_bytes(); + jlong kernel_memory_limit_in_bytes(julong host_mem); + jlong kernel_memory_max_usage_in_bytes(); + void print_version_specific_info(outputStream* st, julong host_mem) override; + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + bool is_read_only() override { + return reader()->is_read_only(); + } + const char* subsystem_path() override { return reader()->subsystem_path(); } + const char* mount_point() override { return reader()->mount_point(); } + const char* cgroup_path() override { return reader()->cgroup_path(); } private: - /* Some container runtimes set limits via cgroup - * hierarchy. If set to true consider also memory.stat - * file if everything else seems unlimited */ - bool _uses_mem_hierarchy; - jlong uses_mem_hierarchy(); - void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } + jlong read_mem_swappiness(); + jlong read_mem_swap(julong host_total_memsw); public: - CgroupV1MemoryController(char *root, char *mountpoint) : CgroupV1Controller(root, mountpoint) { - _uses_mem_hierarchy = false; + CgroupV1MemoryController(const CgroupV1Controller& reader) + : _reader(reader) { + } + +}; + +class CgroupV1CpuController final : public CgroupCpuController { + + private: + CgroupV1Controller _reader; + CgroupV1Controller* reader() { return &_reader; } + public: + int cpu_quota() override; + int cpu_period() override; + int cpu_shares() override; + void set_subsystem_path(const char *cgroup_path) override { + reader()->set_subsystem_path(cgroup_path); + } + bool is_read_only() override { + return reader()->is_read_only(); + } + const char* subsystem_path() override { + return reader()->subsystem_path(); } + const char* mount_point() override { + return reader()->mount_point(); + } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + const char* cgroup_path() override { return reader()->cgroup_path(); } + public: + CgroupV1CpuController(const CgroupV1Controller& reader) : _reader(reader) { + } }; class CgroupV1Subsystem: public CgroupSubsystem { public: - jlong read_memory_limit_in_bytes(); - jlong memory_and_swap_limit_in_bytes(); - jlong memory_soft_limit_in_bytes(); - jlong memory_usage_in_bytes(); - jlong memory_max_usage_in_bytes(); + CgroupV1Subsystem(CgroupV1Controller* cpuset, + CgroupV1CpuController* cpu, + CgroupV1Controller* cpuacct, + CgroupV1Controller* pids, + CgroupV1MemoryController* memory); jlong kernel_memory_usage_in_bytes(); jlong kernel_memory_limit_in_bytes(); @@ -87,47 +155,24 @@ char * cpu_cpuset_cpus(); char * cpu_cpuset_memory_nodes(); - int cpu_quota(); - int cpu_period(); - - int cpu_shares(); - jlong pids_max(); jlong pids_current(); - - void print_version_specific_info(outputStream* st); + bool is_containerized(); const char * container_type() { return "cgroupv1"; } - CachingCgroupController * memory_controller() { return _memory; } - CachingCgroupController * cpu_controller() { return _cpu; } + CachingCgroupController* memory_controller() { return _memory; } + CachingCgroupController* cpu_controller() { return _cpu; } private: /* controllers */ - CachingCgroupController* _memory = nullptr; + CachingCgroupController* _memory = nullptr; CgroupV1Controller* _cpuset = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _cpu = nullptr; CgroupV1Controller* _cpuacct = nullptr; CgroupV1Controller* _pids = nullptr; - char * pids_max_val(); - - jlong read_mem_swappiness(); - jlong read_mem_swap(); - - public: - CgroupV1Subsystem(CgroupV1Controller* cpuset, - CgroupV1Controller* cpu, - CgroupV1Controller* cpuacct, - CgroupV1Controller* pids, - CgroupV1MemoryController* memory) { - _cpuset = cpuset; - _cpu = new CachingCgroupController(cpu); - _cpuacct = cpuacct; - _pids = pids; - _memory = new CachingCgroupController(memory); - } }; #endif // CGROUP_V1_SUBSYSTEM_LINUX_HPP diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -23,6 +23,23 @@ */ #include "cgroupV2Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" + +// Constructor +CgroupV2Controller::CgroupV2Controller(char* mount_path, + char *cgroup_path, + bool ro) : _read_only(ro), + _path(construct_path(mount_path, cgroup_path)) { + _cgroup_path = os::strdup(cgroup_path); + _mount_point = os::strdup(mount_path); +} +// Shallow copy constructor +CgroupV2Controller::CgroupV2Controller(const CgroupV2Controller& o) : + _read_only(o._read_only), + _path(o._path) { + _cgroup_path = o._cgroup_path; + _mount_point = o._mount_point; +} /* cpu_shares * @@ -34,11 +51,12 @@ * -1 for no share setup * OSCONTAINER_ERROR for not supported */ -int CgroupV2Subsystem::cpu_shares() { - GET_CONTAINER_INFO(int, _unified, "/cpu.weight", - "Raw value for CPU Shares is: ", "%d", "%d", shares); +int CgroupV2CpuController::cpu_shares() { + julong shares; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.weight", "Raw value for CPU Shares", shares); + int shares_int = (int)shares; // Convert default value of 100 to no shares setup - if (shares == 100) { + if (shares_int == 100) { log_debug(os, container)("CPU Shares is: %d", -1); return -1; } @@ -50,7 +68,7 @@ // Use the inverse of (x == OCI value, y == cgroupsv2 value): // ((262142 * y - 1)/9999) + 2 = x // - int x = 262142 * shares - 1; + int x = 262142 * shares_int - 1; double frac = x/9999.0; x = ((int)frac) + 2; log_trace(os, container)("Scaled CPU shares value is: %d", x); @@ -82,34 +100,55 @@ * -1 for no quota * OSCONTAINER_ERROR for not supported */ -int CgroupV2Subsystem::cpu_quota() { - char * cpu_quota_str = cpu_quota_val(); - int limit = (int)limit_from_str(cpu_quota_str); +int CgroupV2CpuController::cpu_quota() { + jlong quota_val; + bool is_ok = reader()->read_numerical_tuple_value("/cpu.max", true /* use_first */, "a_val); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + int limit = (int)quota_val; log_trace(os, container)("CPU Quota is: %d", limit); return limit; } -char * CgroupV2Subsystem::cpu_cpuset_cpus() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpuset.cpus", - "cpuset.cpus is: %s", "%1023s", cpus, 1024); +// Constructor +CgroupV2Subsystem::CgroupV2Subsystem(CgroupV2MemoryController * memory, + CgroupV2CpuController* cpu, + CgroupV2Controller unified) : + _unified(unified) { + CgroupUtil::adjust_controller(memory); + CgroupUtil::adjust_controller(cpu); + _memory = new CachingCgroupController(memory); + _cpu = new CachingCgroupController(cpu); +} + +bool CgroupV2Subsystem::is_containerized() { + return _unified.is_read_only() && + _memory->controller()->is_read_only() && + _cpu->controller()->is_read_only(); +} + +char* CgroupV2Subsystem::cpu_cpuset_cpus() { + char cpus[1024]; + CONTAINER_READ_STRING_CHECKED(unified(), "/cpuset.cpus", "cpuset.cpus", cpus, 1024); return os::strdup(cpus); } -char* CgroupV2Subsystem::cpu_quota_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpu.max", - "Raw value for CPU quota is: %s", "%1023s %*d", quota, 1024); - return os::strdup(quota); -} - -char * CgroupV2Subsystem::cpu_cpuset_memory_nodes() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpuset.mems", - "cpuset.mems is: %s", "%1023s", mems, 1024); +char* CgroupV2Subsystem::cpu_cpuset_memory_nodes() { + char mems[1024]; + CONTAINER_READ_STRING_CHECKED(unified(), "/cpuset.mems", "cpuset.mems", mems, 1024); return os::strdup(mems); } -int CgroupV2Subsystem::cpu_period() { - GET_CONTAINER_INFO(int, _unified, "/cpu.max", - "CPU Period is: ", "%d", "%*s %d", period); +int CgroupV2CpuController::cpu_period() { + jlong period_val; + bool is_ok = reader()->read_numerical_tuple_value("/cpu.max", false /* use_first */, &period_val); + if (!is_ok) { + log_trace(os, container)("CPU Period failed: %d", OSCONTAINER_ERROR); + return OSCONTAINER_ERROR; + } + int period = (int)period_val; + log_trace(os, container)("CPU Period is: %d", period); return period; } @@ -122,27 +161,42 @@ * -1 for unlimited * OSCONTAINER_ERROR for not supported */ -jlong CgroupV2Subsystem::memory_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _unified, "/memory.current", - "Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memusage); - return memusage; +jlong CgroupV2MemoryController::memory_usage_in_bytes() { + julong memusage; + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.current", "Memory Usage", memusage); + return (jlong)memusage; } -jlong CgroupV2Subsystem::memory_soft_limit_in_bytes() { - char* mem_soft_limit_str = mem_soft_limit_val(); - return limit_from_str(mem_soft_limit_str); +jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { + jlong mem_soft_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(reader(), "/memory.low", "Memory Soft Limit", mem_soft_limit); + return mem_soft_limit; } -jlong CgroupV2Subsystem::memory_max_usage_in_bytes() { +jlong CgroupV2MemoryController::memory_max_usage_in_bytes() { // Log this string at trace level so as to make tests happy. log_trace(os, container)("Maximum Memory Usage is not supported."); return OSCONTAINER_ERROR; // not supported } -char* CgroupV2Subsystem::mem_soft_limit_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.low", - "Memory Soft Limit is: %s", "%1023s", mem_soft_limit_str, 1024); - return os::strdup(mem_soft_limit_str); +jlong CgroupV2MemoryController::rss_usage_in_bytes() { + julong rss; + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "anon", &rss); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("RSS usage is: " JULONG_FORMAT, rss); + return (jlong)rss; +} + +jlong CgroupV2MemoryController::cache_usage_in_bytes() { + julong cache; + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "file", &cache); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("Cache usage is: " JULONG_FORMAT, cache); + return (jlong)cache; } // Note that for cgroups v2 the actual limits set for swap and @@ -150,17 +204,19 @@ // respectively. In order to properly report a cgroup v1 like // compound value we need to sum the two values. Setting a swap limit // without also setting a memory limit is not allowed. -jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { - char* mem_swp_limit_str = mem_swp_limit_val(); - if (mem_swp_limit_str == nullptr) { +jlong CgroupV2MemoryController::memory_and_swap_limit_in_bytes(julong phys_mem, + julong host_swap /* unused in cg v2 */) { + jlong swap_limit; + bool is_ok = reader()->read_number_handle_max("/memory.swap.max", &swap_limit); + if (!is_ok) { // Some container tests rely on this trace logging to happen. - log_trace(os, container)("Memory and Swap Limit is: %d", OSCONTAINER_ERROR); + log_trace(os, container)("Swap Limit failed: %d", OSCONTAINER_ERROR); // swap disabled at kernel level, treat it as no swap - return read_memory_limit_in_bytes(); + return read_memory_limit_in_bytes(phys_mem); } - jlong swap_limit = limit_from_str(mem_swp_limit_str); + log_trace(os, container)("Swap Limit is: " JLONG_FORMAT, swap_limit); if (swap_limit >= 0) { - jlong memory_limit = read_memory_limit_in_bytes(); + jlong memory_limit = read_memory_limit_in_bytes(phys_mem); assert(memory_limit >= 0, "swap limit without memory limit?"); return memory_limit + swap_limit; } @@ -168,20 +224,22 @@ return swap_limit; } -char* CgroupV2Subsystem::mem_swp_limit_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.max", - "Memory and Swap Limit is: %s", "%1023s", mem_swp_limit_str, 1024); - return os::strdup(mem_swp_limit_str); +// memory.swap.current : total amount of swap currently used by the cgroup and its descendants +static +jlong memory_swap_current_value(CgroupV2Controller* ctrl) { + julong swap_current; + CONTAINER_READ_NUMBER_CHECKED(ctrl, "/memory.swap.current", "Swap currently used", swap_current); + return (jlong)swap_current; } -// memory.swap.current : total amount of swap currently used by the cgroup and its descendants -char* CgroupV2Subsystem::mem_swp_current_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.current", - "Swap currently used is: %s", "%1023s", mem_swp_current_str, 1024); - return os::strdup(mem_swp_current_str); +static +jlong memory_limit_value(CgroupV2Controller* ctrl) { + jlong memory_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(ctrl, "/memory.max", "Memory Limit", memory_limit); + return memory_limit; } -/* memory_limit_in_bytes +/* read_memory_limit_in_bytes * * Return the limit of available memory for this process. * @@ -189,9 +247,8 @@ * memory limit in bytes or * -1 for unlimited, OSCONTAINER_ERROR for an error */ -jlong CgroupV2Subsystem::read_memory_limit_in_bytes() { - char * mem_limit_str = mem_limit_val(); - jlong limit = limit_from_str(mem_limit_str); +jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong phys_mem) { + jlong limit = memory_limit_value(reader()); if (log_is_enabled(Trace, os, container)) { if (limit == -1) { log_trace(os, container)("Memory Limit is: Unlimited"); @@ -199,27 +256,53 @@ log_trace(os, container)("Memory Limit is: " JLONG_FORMAT, limit); } } + if (log_is_enabled(Debug, os, container)) { + julong read_limit = (julong)limit; // avoid signed/unsigned compare + if (limit < 0 || read_limit >= phys_mem) { + const char* reason; + if (limit == -1) { + reason = "unlimited"; + } else if (limit == OSCONTAINER_ERROR) { + reason = "failed"; + } else { + assert(read_limit >= phys_mem, "Expected mem limit to exceed host memory"); + reason = "ignored"; + } + log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, + reason, limit, phys_mem); + } + } return limit; } -char* CgroupV2Subsystem::mem_limit_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.max", - "Raw value for memory limit is: %s", "%1023s", mem_limit_str, 1024); - return os::strdup(mem_limit_str); +static +jlong memory_swap_limit_value(CgroupV2Controller* ctrl) { + jlong swap_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(ctrl, "/memory.swap.max", "Swap Limit", swap_limit); + return swap_limit; +} + +void CgroupV2Controller::set_subsystem_path(const char* cgroup_path) { + if (_path != nullptr) { + os::free(_path); + } + _path = construct_path(_mount_point, cgroup_path); } -void CgroupV2Subsystem::print_version_specific_info(outputStream* st) { - char* mem_swp_current_str = mem_swp_current_val(); - jlong swap_current = limit_from_str(mem_swp_current_str); +// For cgv2 we only need hierarchy walk if the cgroup path isn't '/' (root) +bool CgroupV2Controller::needs_hierarchy_adjustment() { + return strcmp(_cgroup_path, "/") != 0; +} - char* mem_swp_limit_str = mem_swp_limit_val(); - jlong swap_limit = limit_from_str(mem_swp_limit_str); +void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { + jlong swap_current = memory_swap_current_value(reader()); + jlong swap_limit = memory_swap_limit_value(reader()); OSContainer::print_container_helper(st, swap_current, "memory_swap_current_in_bytes"); OSContainer::print_container_helper(st, swap_limit, "memory_swap_max_limit_in_bytes"); } -char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) { +char* CgroupV2Controller::construct_path(char* mount_path, const char* cgroup_path) { stringStream ss; ss.print_raw(mount_path); if (strcmp(cgroup_path, "/") != 0) { @@ -228,12 +311,6 @@ return os::strdup(ss.base()); } -char* CgroupV2Subsystem::pids_max_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/pids.max", - "Maximum number of tasks is: %s", "%1023s", pidsmax, 1024); - return os::strdup(pidsmax); -} - /* pids_max * * Return the maximum number of tasks available to the process @@ -244,8 +321,9 @@ * OSCONTAINER_ERROR for not supported */ jlong CgroupV2Subsystem::pids_max() { - char * pidsmax_str = pids_max_val(); - return limit_from_str(pidsmax_str); + jlong pids_max; + CONTAINER_READ_NUMBER_CHECKED_MAX(unified(), "/pids.max", "Maximum number of tasks", pids_max); + return pids_max; } /* pids_current @@ -257,7 +335,7 @@ * OSCONTAINER_ERROR for not supported */ jlong CgroupV2Subsystem::pids_current() { - GET_CONTAINER_INFO(jlong, _unified, "/pids.current", - "Current number of tasks is: ", JLONG_FORMAT, JLONG_FORMAT, pids_current); + julong pids_current; + CONTAINER_READ_NUMBER_CHECKED(unified(), "/pids.current", "Current number of tasks", pids_current); return pids_current; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Red Hat Inc. + * Copyright (c) 2020, 2024, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,71 +26,116 @@ #define CGROUP_V2_SUBSYSTEM_LINUX_HPP #include "cgroupSubsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" class CgroupV2Controller: public CgroupController { private: - /* the mount path of the cgroup v2 hierarchy */ - char *_mount_path; - /* The cgroup path for the controller */ - char *_cgroup_path; + bool _read_only; /* Constructed full path to the subsystem directory */ char *_path; - static char* construct_path(char* mount_path, char *cgroup_path); + static char* construct_path(char* mount_path, const char *cgroup_path); public: - CgroupV2Controller(char * mount_path, char *cgroup_path) { - _mount_path = mount_path; - _cgroup_path = os::strdup(cgroup_path); - _path = construct_path(mount_path, cgroup_path); + CgroupV2Controller(char* mount_path, char *cgroup_path, bool ro); + // Shallow copy constructor + CgroupV2Controller(const CgroupV2Controller& o); + ~CgroupV2Controller() { + // At least one controller exists with references to the paths } - char *subsystem_path() { return _path; } + const char* subsystem_path() override { return _path; } + bool needs_hierarchy_adjustment() override; + // Allow for optional updates of the subsystem path + void set_subsystem_path(const char* cgroup_path); + bool is_read_only() override { return _read_only; } +}; + +class CgroupV2CpuController: public CgroupCpuController { + private: + CgroupV2Controller _reader; + CgroupV2Controller* reader() { return &_reader; } + public: + CgroupV2CpuController(const CgroupV2Controller& reader) : _reader(reader) { + } + int cpu_quota() override; + int cpu_period() override; + int cpu_shares() override; + bool is_read_only() override { + return reader()->is_read_only(); + } + const char* subsystem_path() override { + return reader()->subsystem_path(); + } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + void set_subsystem_path(const char* cgroup_path) override { + reader()->set_subsystem_path(cgroup_path); + } + const char* mount_point() override { return reader()->mount_point(); } + const char* cgroup_path() override { return reader()->cgroup_path(); } +}; + +class CgroupV2MemoryController final: public CgroupMemoryController { + private: + CgroupV2Controller _reader; + CgroupV2Controller* reader() { return &_reader; } + public: + CgroupV2MemoryController(const CgroupV2Controller& reader) : _reader(reader) { + } + + jlong read_memory_limit_in_bytes(julong upper_bound) override; + jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swp) override; + jlong memory_soft_limit_in_bytes(julong upper_bound) override; + jlong memory_usage_in_bytes() override; + jlong memory_max_usage_in_bytes() override; + jlong rss_usage_in_bytes() override; + jlong cache_usage_in_bytes() override; + void print_version_specific_info(outputStream* st, julong host_mem) override; + bool is_read_only() override { + return reader()->is_read_only(); + } + const char* subsystem_path() override { + return reader()->subsystem_path(); + } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + void set_subsystem_path(const char* cgroup_path) override { + reader()->set_subsystem_path(cgroup_path); + } + const char* mount_point() override { return reader()->mount_point(); } + const char* cgroup_path() override { return reader()->cgroup_path(); } }; class CgroupV2Subsystem: public CgroupSubsystem { private: /* One unified controller */ - CgroupController* _unified = nullptr; + CgroupV2Controller _unified; /* Caching wrappers for cpu/memory metrics */ - CachingCgroupController* _memory = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _memory = nullptr; + CachingCgroupController* _cpu = nullptr; - char *mem_limit_val(); - char *mem_swp_limit_val(); - char *mem_swp_current_val(); - char *mem_soft_limit_val(); - char *cpu_quota_val(); - char *pids_max_val(); + CgroupV2Controller* unified() { return &_unified; } public: - CgroupV2Subsystem(CgroupController * unified) { - _unified = unified; - _memory = new CachingCgroupController(unified); - _cpu = new CachingCgroupController(unified); - } - - jlong read_memory_limit_in_bytes(); - int cpu_quota(); - int cpu_period(); - int cpu_shares(); - jlong memory_and_swap_limit_in_bytes(); - jlong memory_soft_limit_in_bytes(); - jlong memory_usage_in_bytes(); - jlong memory_max_usage_in_bytes(); - - char * cpu_cpuset_cpus(); - char * cpu_cpuset_memory_nodes(); - jlong pids_max(); - jlong pids_current(); + CgroupV2Subsystem(CgroupV2MemoryController * memory, + CgroupV2CpuController* cpu, + CgroupV2Controller unified); + + char * cpu_cpuset_cpus() override; + char * cpu_cpuset_memory_nodes() override; + jlong pids_max() override; + jlong pids_current() override; - void print_version_specific_info(outputStream* st); + bool is_containerized() override; - const char * container_type() { + const char * container_type() override { return "cgroupv2"; } - CachingCgroupController * memory_controller() { return _memory; } - CachingCgroupController * cpu_controller() { return _cpu; } + CachingCgroupController* memory_controller() override { return _memory; } + CachingCgroupController* cpu_controller() override { return _cpu; } }; #endif // CGROUP_V2_SUBSYSTEM_LINUX_HPP diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/osContainer_linux.cpp openjdk-21-21.0.9+10/src/hotspot/os/linux/osContainer_linux.cpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/osContainer_linux.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/osContainer_linux.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -58,8 +58,43 @@ if (cgroup_subsystem == nullptr) { return; // Required subsystem files not found or other error } - - _is_containerized = true; + /* + * In order to avoid a false positive on is_containerized() on + * Linux systems outside a container *and* to ensure compatibility + * with in-container usage, we detemine is_containerized() by two + * steps: + * 1.) Determine if all the cgroup controllers are mounted read only. + * If yes, is_containerized() == true. Otherwise, do the fallback + * in 2.) + * 2.) Query for memory and cpu limits. If any limit is set, we set + * is_containerized() == true. + * + * Step 1.) covers the basic in container use-cases. Step 2.) ensures + * that limits enforced by other means (e.g. systemd slice) are properly + * detected. + */ + const char *reason; + bool any_mem_cpu_limit_present = false; + bool controllers_read_only = cgroup_subsystem->is_containerized(); + if (controllers_read_only) { + // in-container case + reason = " because all controllers are mounted read-only (container case)"; + } else { + // We can be in one of two cases: + // 1.) On a physical Linux system without any limit + // 2.) On a physical Linux system with a limit enforced by other means (like systemd slice) + any_mem_cpu_limit_present = cgroup_subsystem->memory_limit_in_bytes() > 0 || + os::Linux::active_processor_count() != cgroup_subsystem->active_processor_count(); + if (any_mem_cpu_limit_present) { + reason = " because either a cpu or a memory limit is present"; + } else { + reason = " because no cpu or memory limit is present"; + } + } + _is_containerized = controllers_read_only || any_mem_cpu_limit_present; + log_debug(os, container)("OSContainer::init: is_containerized() = %s%s", + _is_containerized ? "true" : "false", + reason); } const char * OSContainer::container_type() { @@ -92,6 +127,16 @@ return cgroup_subsystem->memory_max_usage_in_bytes(); } +jlong OSContainer::rss_usage_in_bytes() { + assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); + return cgroup_subsystem->rss_usage_in_bytes(); +} + +jlong OSContainer::cache_usage_in_bytes() { + assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); + return cgroup_subsystem->cache_usage_in_bytes(); +} + void OSContainer::print_version_specific_info(outputStream* st) { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); cgroup_subsystem->print_version_specific_info(st); diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/osContainer_linux.hpp openjdk-21-21.0.9+10/src/hotspot/os/linux/osContainer_linux.hpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/osContainer_linux.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/osContainer_linux.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -55,6 +55,8 @@ static jlong memory_soft_limit_in_bytes(); static jlong memory_usage_in_bytes(); static jlong memory_max_usage_in_bytes(); + static jlong rss_usage_in_bytes(); + static jlong cache_usage_in_bytes(); static int active_processor_count(); diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/linux/os_linux.cpp openjdk-21-21.0.9+10/src/hotspot/os/linux/os_linux.cpp --- openjdk-21-21.0.8+9/src/hotspot/os/linux/os_linux.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/linux/os_linux.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -2380,6 +2380,8 @@ OSContainer::print_container_helper(st, OSContainer::memory_soft_limit_in_bytes(), "memory_soft_limit_in_bytes"); OSContainer::print_container_helper(st, OSContainer::memory_usage_in_bytes(), "memory_usage_in_bytes"); OSContainer::print_container_helper(st, OSContainer::memory_max_usage_in_bytes(), "memory_max_usage_in_bytes"); + OSContainer::print_container_helper(st, OSContainer::rss_usage_in_bytes(), "rss_usage_in_bytes"); + OSContainer::print_container_helper(st, OSContainer::cache_usage_in_bytes(), "cache_usage_in_bytes"); OSContainer::print_version_specific_info(st); diff -Nru openjdk-21-21.0.8+9/src/hotspot/os/posix/signals_posix.cpp openjdk-21-21.0.9+10/src/hotspot/os/posix/signals_posix.cpp --- openjdk-21-21.0.8+9/src/hotspot/os/posix/signals_posix.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os/posix/signals_posix.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -48,6 +48,13 @@ #include +#define SEGV_BNDERR_value 3 + +#if defined(SEGV_BNDERR) +STATIC_ASSERT(SEGV_BNDERR == SEGV_BNDERR_value); +#else +#define SEGV_BNDERR SEGV_BNDERR_value +#endif static const char* get_signal_name(int sig, char* out, size_t outlen); @@ -981,6 +988,9 @@ { SIGFPE, FPE_FLTSUB, "FPE_FLTSUB", "Subscript out of range." }, { SIGSEGV, SEGV_MAPERR, "SEGV_MAPERR", "Address not mapped to object." }, { SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for mapped object." }, +#if defined(LINUX) + { SIGSEGV, SEGV_BNDERR, "SEGV_BNDERR", "Failed address bound checks." }, +#endif #if defined(AIX) // no explanation found what keyerr would be { SIGSEGV, SEGV_KEYERR, "SEGV_KEYERR", "key error" }, diff -Nru openjdk-21-21.0.8+9/src/hotspot/os_cpu/aix_ppc/javaThread_aix_ppc.cpp openjdk-21-21.0.9+10/src/hotspot/os_cpu/aix_ppc/javaThread_aix_ppc.cpp --- openjdk-21-21.0.8+9/src/hotspot/os_cpu/aix_ppc/javaThread_aix_ppc.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os_cpu/aix_ppc/javaThread_aix_ppc.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2014 SAP SE. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * Copyright (c) 2022, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,6 +28,7 @@ #include "memory/metaspace.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" +#include "runtime/os.inline.hpp" frame JavaThread::pd_last_frame() { assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); @@ -47,9 +48,17 @@ if (has_last_Java_frame() && frame_anchor()->walkable()) { intptr_t* sp = last_Java_sp(); address pc = _anchor.last_Java_pc(); - // pc can be seen as null because not all writers use store pc + release store sp. - // Simply discard the sample in this very rare case. - if (pc == nullptr) return false; + if (pc == nullptr) { + // This is not uncommon. Many c1/c2 runtime stubs do not set the pc in the anchor. + intptr_t* top_sp = os::Aix::ucontext_get_sp((const ucontext_t*)ucontext); + if ((uint64_t)sp <= ((frame::common_abi*)top_sp)->callers_sp) { + // The interrupt occurred either in the last java frame or in its direct callee. + // We cannot be sure that the link register LR was already saved to the + // java frame. Therefore we discard this sample. + return false; + } + // The last java pc will be found in the abi part of the last java frame. + } *fr_addr = frame(sp, pc); return true; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/os_cpu/linux_ppc/javaThread_linux_ppc.cpp openjdk-21-21.0.9+10/src/hotspot/os_cpu/linux_ppc/javaThread_linux_ppc.cpp --- openjdk-21-21.0.8+9/src/hotspot/os_cpu/linux_ppc/javaThread_linux_ppc.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/os_cpu/linux_ppc/javaThread_linux_ppc.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2022 SAP SE. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. 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 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "memory/metaspace.hpp" +#include "os_linux.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" @@ -46,9 +47,17 @@ if (has_last_Java_frame() && frame_anchor()->walkable()) { intptr_t* sp = last_Java_sp(); address pc = _anchor.last_Java_pc(); - // pc can be seen as null because not all writers use store pc + release store sp. - // Simply discard the sample in this very rare case. - if (pc == nullptr) return false; + if (pc == nullptr) { + // This is not uncommon. Many c1/c2 runtime stubs do not set the pc in the anchor. + intptr_t* top_sp = os::Linux::ucontext_get_sp((const ucontext_t*)ucontext); + if ((uint64_t)sp <= ((frame::common_abi*)top_sp)->callers_sp) { + // The interrupt occurred either in the last java frame or in its direct callee. + // We cannot be sure that the link register LR was already saved to the + // java frame. Therefore we discard this sample. + return false; + } + // The last java pc will be found in the abi part of the last java frame. + } *fr_addr = frame(sp, pc); return true; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/adlc/output_h.cpp openjdk-21-21.0.9+10/src/hotspot/share/adlc/output_h.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/adlc/output_h.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/adlc/output_h.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -856,7 +856,8 @@ fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " void step(uint cycles) {\n"); fprintf(fp_hpp, " _used = 0;\n"); - fprintf(fp_hpp, " _mask <<= cycles;\n"); + fprintf(fp_hpp, " uint max_shift = 8 * sizeof(_mask) - 1;\n"); + fprintf(fp_hpp, " _mask <<= (cycles < max_shift) ? cycles : max_shift;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " friend class Pipeline_Use;\n"); fprintf(fp_hpp, "};\n\n"); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/c1/c1_Compilation.cpp openjdk-21-21.0.9+10/src/hotspot/share/c1/c1_Compilation.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/c1/c1_Compilation.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/c1/c1_Compilation.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -33,6 +33,7 @@ #include "c1/c1_ValueMap.hpp" #include "c1/c1_ValueStack.hpp" #include "code/debugInfoRec.hpp" +#include "compiler/compilationLog.hpp" #include "compiler/compileLog.hpp" #include "compiler/compilerDirectives.hpp" #include "memory/resourceArea.hpp" @@ -638,6 +639,13 @@ void Compilation::bailout(const char* msg) { assert(msg != nullptr, "bailout message must exist"); + // record the bailout for hserr envlog + if (CompilationLog::log() != nullptr) { + CompilerThread* thread = CompilerThread::current(); + CompileTask* task = thread->task(); + CompilationLog::log()->log_failure(thread, task, msg, nullptr); + } + if (!bailed_out()) { // keep first bailout message if (PrintCompilation || PrintBailouts) tty->print_cr("compilation bailout: %s", msg); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/cds/classListParser.cpp openjdk-21-21.0.9+10/src/hotspot/share/cds/classListParser.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/cds/classListParser.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/cds/classListParser.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -472,7 +472,9 @@ THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()); } - InstanceKlass* k = UnregisteredClasses::load_class(class_name, _source, CHECK_NULL); + ResourceMark rm; + char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source)); + InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL); if (k->local_interfaces()->length() != _interfaces->length()) { print_specified_interfaces(); print_actual_interfaces(k); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/cds/classListWriter.cpp openjdk-21-21.0.9+10/src/hotspot/share/cds/classListWriter.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/cds/classListWriter.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/cds/classListWriter.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -171,6 +171,8 @@ } } + // NB: the string following "source: " is not really a proper file name, but rather + // a truncated URI referring to a file. It must be decoded after reading. #ifdef _WINDOWS // "file:/C:/dir/foo.jar" -> "C:/dir/foo.jar" stream->print(" source: %s", cfs->source() + 6); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/cds/filemap.cpp openjdk-21-21.0.9+10/src/hotspot/share/cds/filemap.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/cds/filemap.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/cds/filemap.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -586,7 +586,7 @@ // skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table() ResourceMark rm; - const char* file = ClassLoader::skip_uri_protocol(location->as_C_string()); + const char* file = ClassLoader::uri_to_path(location->as_C_string()); for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) { SharedClassPathEntry* ent = shared_path(i); assert(ent->in_named_module(), "must be"); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/ci/ciEnv.cpp openjdk-21-21.0.9+10/src/hotspot/share/ci/ciEnv.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/ci/ciEnv.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/ci/ciEnv.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1230,6 +1230,15 @@ // ------------------------------------------------------------------ // ciEnv::record_failure() void ciEnv::record_failure(const char* reason) { + // record the bailout for hserr envlog + if (reason != nullptr) { + if (CompilationLog::log() != nullptr) { + CompilerThread* thread = CompilerThread::current(); + CompileTask* task = thread->task(); + CompilationLog::log()->log_failure(thread, task, reason, nullptr); + } + } + if (_failure_reason.get() == nullptr) { // Record the first failure reason. _failure_reason.set(reason); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/classLoader.cpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoader.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/classLoader.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoader.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -78,6 +78,9 @@ #include "utilities/macros.hpp" #include "utilities/utf8.hpp" +#include +#include + // Entry point in java.dll for path canonicalization typedef int (*canonicalize_fn_t)(const char *orig, char *out, int len); @@ -1224,7 +1227,7 @@ } #if INCLUDE_CDS -char* ClassLoader::skip_uri_protocol(char* source) { +static const char* skip_uri_protocol(const char* source) { if (strncmp(source, "file:", 5) == 0) { // file: protocol path could start with file:/ or file:/// // locate the char after all the forward slashes @@ -1243,6 +1246,47 @@ return source; } +static char decode_percent_encoded(const char *str, size_t& index) { + if (str[index] == '%' + && isxdigit(str[index + 1]) + && isxdigit(str[index + 2])) { + char hex[3]; + hex[0] = str[index + 1]; + hex[1] = str[index + 2]; + hex[2] = '\0'; + index += 2; + return (char) strtol(hex, NULL, 16); + } + return str[index]; +} + +char* ClassLoader::uri_to_path(const char* uri) { + const size_t len = strlen(uri) + 1; + char* path = NEW_RESOURCE_ARRAY(char, len); + + uri = skip_uri_protocol(uri); + + if (strncmp(uri, "//", 2) == 0) { + // Skip the empty "authority" part + uri += 2; + } + +#ifdef _WINDOWS + if (uri[0] == '/') { + // Absolute path name on Windows does not begin with a slash + uri += 1; + } +#endif + + size_t path_index = 0; + for (size_t i = 0; i < strlen(uri); ++i) { + char decoded = decode_percent_encoded(uri, i); + path[path_index++] = decoded; + } + path[path_index] = '\0'; + return path; +} + // Record the shared classpath index and loader type for classes loaded // by the builtin loaders at dump time. void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, @@ -1276,7 +1320,7 @@ // Save the path from the file: protocol or the module name from the jrt: protocol // if no protocol prefix is found, path is the same as stream->source(). This path // must be valid since the class has been successfully parsed. - char* path = skip_uri_protocol(src); + const char* path = ClassLoader::uri_to_path(src); assert(path != nullptr, "sanity"); for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) { SharedClassPathEntry* ent = FileMapInfo::shared_path(i); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/classLoader.hpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoader.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/classLoader.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoader.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -370,7 +370,7 @@ // entries during shared classpath setup time. static int num_module_path_entries(); static void exit_with_path_failure(const char* error, const char* message); - static char* skip_uri_protocol(char* source); + static char* uri_to_path(const char* uri); static void record_result(JavaThread* current, InstanceKlass* ik, const ClassFileStream* stream, bool redefined); #endif diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/classLoaderExt.cpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoaderExt.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/classLoaderExt.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/classLoaderExt.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -98,12 +98,10 @@ ModulePathsGatherer(JavaThread* current, GrowableArray* module_paths) : _current(current), _module_paths(module_paths) {} void do_module(ModuleEntry* m) { - char* path = m->location()->as_C_string(); - if (strncmp(path, "file:", 5) == 0) { - path = ClassLoader::skip_uri_protocol(path); - char* path_copy = NEW_RESOURCE_ARRAY(char, strlen(path) + 1); - strcpy(path_copy, path); - _module_paths->append(path_copy); + char* uri = m->location()->as_C_string(); + if (strncmp(uri, "file:", 5) == 0) { + char* path = ClassLoader::uri_to_path(uri); + _module_paths->append(path); } } }; diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/javaClasses.cpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/javaClasses.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -4435,28 +4435,31 @@ // Support for java_lang_invoke_CallSite int java_lang_invoke_CallSite::_target_offset; -int java_lang_invoke_CallSite::_context_offset; +int java_lang_invoke_CallSite::_vmdependencies_offset; +int java_lang_invoke_CallSite::_last_cleanup_offset; #define CALLSITE_FIELDS_DO(macro) \ macro(_target_offset, k, "target", java_lang_invoke_MethodHandle_signature, false); \ - macro(_context_offset, k, "context", java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, false) void java_lang_invoke_CallSite::compute_offsets() { InstanceKlass* k = vmClasses::CallSite_klass(); CALLSITE_FIELDS_DO(FIELD_COMPUTE_OFFSET); + CALLSITE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } #if INCLUDE_CDS void java_lang_invoke_CallSite::serialize_offsets(SerializeClosure* f) { CALLSITE_FIELDS_DO(FIELD_SERIALIZE_OFFSET); + CALLSITE_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); } #endif -oop java_lang_invoke_CallSite::context_no_keepalive(oop call_site) { +DependencyContext java_lang_invoke_CallSite::vmdependencies(oop call_site) { assert(java_lang_invoke_CallSite::is_instance(call_site), ""); - - oop dep_oop = call_site->obj_field_access(_context_offset); - return dep_oop; + nmethodBucket* volatile* vmdeps_addr = call_site->field_addr(_vmdependencies_offset); + volatile uint64_t* last_cleanup_addr = call_site->field_addr(_last_cleanup_offset); + DependencyContext dep_ctx(vmdeps_addr, last_cleanup_addr); + return dep_ctx; } // Support for java_lang_invoke_ConstantCallSite @@ -4477,30 +4480,6 @@ } #endif -// Support for java_lang_invoke_MethodHandleNatives_CallSiteContext - -int java_lang_invoke_MethodHandleNatives_CallSiteContext::_vmdependencies_offset; -int java_lang_invoke_MethodHandleNatives_CallSiteContext::_last_cleanup_offset; - -void java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets() { - InstanceKlass* k = vmClasses::Context_klass(); - CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); -} - -#if INCLUDE_CDS -void java_lang_invoke_MethodHandleNatives_CallSiteContext::serialize_offsets(SerializeClosure* f) { - CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET); -} -#endif - -DependencyContext java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) { - assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); - nmethodBucket* volatile* vmdeps_addr = call_site->field_addr(_vmdependencies_offset); - volatile uint64_t* last_cleanup_addr = call_site->field_addr(_last_cleanup_offset); - DependencyContext dep_ctx(vmdeps_addr, last_cleanup_addr); - return dep_ctx; -} - // Support for java_security_AccessControlContext int java_security_AccessControlContext::_context_offset; @@ -5242,7 +5221,6 @@ f(java_lang_invoke_MethodType) \ f(java_lang_invoke_CallSite) \ f(java_lang_invoke_ConstantCallSite) \ - f(java_lang_invoke_MethodHandleNatives_CallSiteContext) \ f(java_security_AccessControlContext) \ f(java_lang_reflect_AccessibleObject) \ f(java_lang_reflect_Method) \ @@ -5316,7 +5294,6 @@ // constant pool entries, so excluding them shouldn't affect the archiving of static fields. klass == vmClasses::ResolvedMethodName_klass() || klass == vmClasses::MemberName_klass() || - klass == vmClasses::Context_klass() || // It's problematic to archive Reference objects. One of the reasons is that // Reference::discovered may pull in unwanted objects (see JDK-8284336) klass->is_subclass_of(vmClasses::Reference_klass())) { diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/javaClasses.hpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/javaClasses.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1368,13 +1368,17 @@ // Interface to java.lang.invoke.CallSite objects +#define CALLSITE_INJECTED_FIELDS(macro) \ + macro(java_lang_invoke_CallSite, vmdependencies, intptr_signature, false) \ + macro(java_lang_invoke_CallSite, last_cleanup, long_signature, false) class java_lang_invoke_CallSite: AllStatic { friend class JavaClasses; private: static int _target_offset; - static int _context_offset; + static int _vmdependencies_offset; + static int _last_cleanup_offset; static void compute_offsets(); @@ -1385,7 +1389,7 @@ static void set_target( oop site, oop target); static void set_target_volatile( oop site, oop target); - static oop context_no_keepalive(oop site); + static DependencyContext vmdependencies(oop call_site); // Testers static bool is_subclass(Klass* klass) { @@ -1395,7 +1399,6 @@ // Accessors for code generation: static int target_offset() { CHECK_INIT(_target_offset); } - static int context_offset() { CHECK_INIT(_context_offset); } }; // Interface to java.lang.invoke.ConstantCallSite objects @@ -1419,35 +1422,6 @@ } static bool is_instance(oop obj); }; - -// Interface to java.lang.invoke.MethodHandleNatives$CallSiteContext objects - -#define CALLSITECONTEXT_INJECTED_FIELDS(macro) \ - macro(java_lang_invoke_MethodHandleNatives_CallSiteContext, vmdependencies, intptr_signature, false) \ - macro(java_lang_invoke_MethodHandleNatives_CallSiteContext, last_cleanup, long_signature, false) - -class DependencyContext; - -class java_lang_invoke_MethodHandleNatives_CallSiteContext : AllStatic { - friend class JavaClasses; - -private: - static int _vmdependencies_offset; - static int _last_cleanup_offset; - - static void compute_offsets(); - -public: - static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN; - // Accessors - static DependencyContext vmdependencies(oop context); - - // Testers - static bool is_subclass(Klass* klass) { - return klass->is_subclass_of(vmClasses::Context_klass()); - } - static bool is_instance(oop obj); -}; // Interface to java.security.AccessControlContext objects diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/javaClasses.inline.hpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.inline.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/javaClasses.inline.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClasses.inline.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -259,10 +259,6 @@ return obj != nullptr && is_subclass(obj->klass()); } -inline bool java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(oop obj) { - return obj != nullptr && is_subclass(obj->klass()); -} - inline bool java_lang_invoke_MemberName::is_instance(oop obj) { return obj != nullptr && obj->klass() == vmClasses::MemberName_klass(); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/javaClassesImpl.hpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClassesImpl.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/javaClassesImpl.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/javaClassesImpl.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -35,7 +35,7 @@ CLASSLOADER_INJECTED_FIELDS(macro) \ RESOLVEDMETHOD_INJECTED_FIELDS(macro) \ MEMBERNAME_INJECTED_FIELDS(macro) \ - CALLSITECONTEXT_INJECTED_FIELDS(macro) \ + CALLSITE_INJECTED_FIELDS(macro) \ STACKFRAMEINFO_INJECTED_FIELDS(macro) \ MODULE_INJECTED_FIELDS(macro) \ THREAD_INJECTED_FIELDS(macro) \ diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/stackMapTable.cpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/stackMapTable.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/stackMapTable.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/stackMapTable.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -122,8 +122,16 @@ } void StackMapTable::check_jump_target( - StackMapFrame* frame, int32_t target, TRAPS) const { + StackMapFrame* frame, int bci, int offset, TRAPS) const { ErrorContext ctx; + // Jump targets must be within the method and the method size is limited. See JVMS 4.11 + int min_offset = -1 * max_method_code_size; + if (offset < min_offset || offset > max_method_code_size) { + frame->verifier()->verify_error(ErrorContext::bad_stackmap(bci, frame), + "Illegal target of jump or branch (bci %d + offset %d)", bci, offset); + return; + } + int target = bci + offset; bool match = match_stackmap( frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier())); if (!match || (target < 0 || target >= _code_length)) { diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/stackMapTable.hpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/stackMapTable.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/stackMapTable.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/stackMapTable.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -69,7 +69,7 @@ // Check jump instructions. Make sure there are no uninitialized // instances on backward branch. - void check_jump_target(StackMapFrame* frame, int32_t target, TRAPS) const; + void check_jump_target(StackMapFrame* frame, int bci, int offset, TRAPS) const; // The following methods are only used inside this class. diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/verifier.cpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/verifier.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/verifier.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/verifier.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -791,7 +791,6 @@ // Merge with the next instruction { u2 index; - int target; VerificationType type, type2; VerificationType atype; @@ -1607,9 +1606,8 @@ case Bytecodes::_ifle: current_frame.pop_stack( VerificationType::integer_type(), CHECK_VERIFY(this)); - target = bcs.dest(); stackmap_table.check_jump_target( - ¤t_frame, target, CHECK_VERIFY(this)); + ¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_if_acmpeq : case Bytecodes::_if_acmpne : @@ -1620,19 +1618,16 @@ case Bytecodes::_ifnonnull : current_frame.pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); - target = bcs.dest(); stackmap_table.check_jump_target - (¤t_frame, target, CHECK_VERIFY(this)); + (¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_goto : - target = bcs.dest(); stackmap_table.check_jump_target( - ¤t_frame, target, CHECK_VERIFY(this)); + ¤t_frame, bcs.bci(), bcs.get_offset_s2(), CHECK_VERIFY(this)); no_control_flow = true; break; case Bytecodes::_goto_w : - target = bcs.dest_w(); stackmap_table.check_jump_target( - ¤t_frame, target, CHECK_VERIFY(this)); + ¤t_frame, bcs.bci(), bcs.get_offset_s4(), CHECK_VERIFY(this)); no_control_flow = true; break; case Bytecodes::_tableswitch : case Bytecodes::_lookupswitch : @@ -2282,15 +2277,14 @@ } } } - int target = bci + default_offset; - stackmap_table->check_jump_target(current_frame, target, CHECK_VERIFY(this)); + stackmap_table->check_jump_target(current_frame, bci, default_offset, CHECK_VERIFY(this)); for (int i = 0; i < keys; i++) { // Because check_jump_target() may safepoint, the bytecode could have // moved, which means 'aligned_bcp' is no good and needs to be recalculated. aligned_bcp = align_up(bcs->bcp() + 1, jintSize); - target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize); + int offset = (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize); stackmap_table->check_jump_target( - current_frame, target, CHECK_VERIFY(this)); + current_frame, bci, offset, CHECK_VERIFY(this)); } NOT_PRODUCT(aligned_bcp = nullptr); // no longer valid at this point } @@ -2549,8 +2543,13 @@ break; case Bytecodes::_goto: - case Bytecodes::_goto_w: - target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w()); + case Bytecodes::_goto_w: { + int offset = (opcode == Bytecodes::_goto ? bcs.get_offset_s2() : bcs.get_offset_s4()); + int min_offset = -1 * max_method_code_size; + // Check offset for overflow + if (offset < min_offset || offset > max_method_code_size) return false; + + target = bci + offset; if (visited_branches->contains(bci)) { if (bci_stack->is_empty()) { if (handler_stack->is_empty()) { @@ -2571,6 +2570,7 @@ visited_branches->append(bci); } break; + } // Check that all switch alternatives end in 'athrow' bytecodes. Since it // is difficult to determine where each switch alternative ends, parse @@ -2607,7 +2607,10 @@ // Push the switch alternatives onto the stack. for (int i = 0; i < keys; i++) { - u4 target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize); + int min_offset = -1 * max_method_code_size; + int offset = (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize); + if (offset < min_offset || offset > max_method_code_size) return false; + u4 target = bci + offset; if (target > code_length) return false; bci_stack->push(target); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/vmClassMacros.hpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/vmClassMacros.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/vmClassMacros.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/vmClassMacros.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -129,7 +129,6 @@ do_klass(ABIDescriptor_klass, jdk_internal_foreign_abi_ABIDescriptor ) \ do_klass(VMStorage_klass, jdk_internal_foreign_abi_VMStorage ) \ do_klass(CallConv_klass, jdk_internal_foreign_abi_CallConv ) \ - do_klass(Context_klass, java_lang_invoke_MethodHandleNatives_CallSiteContext ) \ do_klass(ConstantCallSite_klass, java_lang_invoke_ConstantCallSite ) \ do_klass(MutableCallSite_klass, java_lang_invoke_MutableCallSite ) \ do_klass(VolatileCallSite_klass, java_lang_invoke_VolatileCallSite ) \ diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/classfile/vmSymbols.hpp openjdk-21-21.0.9+10/src/hotspot/share/classfile/vmSymbols.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/classfile/vmSymbols.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/classfile/vmSymbols.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -341,11 +341,9 @@ template(java_lang_invoke_MemberName, "java/lang/invoke/MemberName") \ template(java_lang_invoke_ResolvedMethodName, "java/lang/invoke/ResolvedMethodName") \ template(java_lang_invoke_MethodHandleNatives, "java/lang/invoke/MethodHandleNatives") \ - template(java_lang_invoke_MethodHandleNatives_CallSiteContext, "java/lang/invoke/MethodHandleNatives$CallSiteContext") \ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ template(java_lang_invoke_InjectedProfile_signature, "Ljava/lang/invoke/InjectedProfile;") \ template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ - template(java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, "Ljava/lang/invoke/MethodHandleNatives$CallSiteContext;") \ /* internal up-calls made only by the JVM, via class sun.invoke.MethodHandleNatives: */ \ template(findMethodHandleType_name, "findMethodHandleType") \ template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;") \ diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/code/dependencyContext.cpp openjdk-21-21.0.9+10/src/hotspot/share/code/dependencyContext.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/code/dependencyContext.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/code/dependencyContext.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -168,12 +168,6 @@ } } -nmethodBucket* DependencyContext::release_and_get_next_not_unloading(nmethodBucket* b) { - nmethodBucket* next = b->next_not_unloading(); - release(b); - return next; - } - // // Invalidate all dependencies in the context void DependencyContext::remove_all_dependents() { @@ -214,18 +208,6 @@ set_dependencies(nullptr); } -void DependencyContext::remove_and_mark_for_deoptimization_all_dependents(DeoptimizationScope* deopt_scope) { - nmethodBucket* b = dependencies_not_unloading(); - set_dependencies(nullptr); - while (b != nullptr) { - nmethod* nm = b->get_nmethod(); - // Also count already (concurrently) marked nmethods to make sure - // deoptimization is triggered before execution in this thread continues. - deopt_scope->mark(nm); - b = release_and_get_next_not_unloading(b); - } -} - #ifndef PRODUCT void DependencyContext::print_dependent_nmethods(bool verbose) { int idx = 0; diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/code/dependencyContext.hpp openjdk-21-21.0.9+10/src/hotspot/share/code/dependencyContext.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/code/dependencyContext.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/code/dependencyContext.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -63,7 +63,7 @@ // // Utility class to manipulate nmethod dependency context. // Dependency context can be attached either to an InstanceKlass (_dep_context field) -// or CallSiteContext oop for call_site_target dependencies (see javaClasses.hpp). +// or CallSite oop for call_site_target dependencies (see javaClasses.hpp). // DependencyContext class operates on some location which holds a nmethodBucket* value // and uint64_t integer recording the safepoint counter at the last cleanup. // @@ -92,7 +92,6 @@ #ifdef ASSERT // Safepoints are forbidden during DC lifetime. GC can invalidate // _dependency_context_addr if it relocates the holder - // (e.g. CallSiteContext Java object). SafepointStateTracker _safepoint_tracker; DependencyContext(nmethodBucket* volatile* bucket_addr, volatile uint64_t* last_cleanup_addr) @@ -114,9 +113,7 @@ void mark_dependent_nmethods(DeoptimizationScope* deopt_scope, DepChange& changes); void add_dependent_nmethod(nmethod* nm); void remove_all_dependents(); - void remove_and_mark_for_deoptimization_all_dependents(DeoptimizationScope* deopt_scope); void clean_unloading_dependents(); - static nmethodBucket* release_and_get_next_not_unloading(nmethodBucket* b); static void purge_dependency_contexts(); static void release(nmethodBucket* b); static void cleaning_start(); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/compiler/compilationLog.cpp openjdk-21-21.0.9+10/src/hotspot/share/compiler/compilationLog.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/compiler/compilationLog.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/compiler/compilationLog.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -52,7 +52,11 @@ void CompilationLog::log_failure(JavaThread* thread, CompileTask* task, const char* reason, const char* retry_message) { StringLogMessage lm; - lm.print("%4d COMPILE SKIPPED: %s", task->compile_id(), reason); + if (task == nullptr) { + lm.print("Id not known, task was 0; COMPILE SKIPPED: %s", reason); + } else { + lm.print("%4d COMPILE SKIPPED: %s", task->compile_id(), reason); + } if (retry_message != nullptr) { lm.append(" (%s)", retry_message); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, 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 @@ -39,9 +39,9 @@ virtual void do_card_ptr(CardValue* card_ptr, uint worker_id) = 0; // Process all the card_ptrs in node. - void apply_to_buffer(BufferNode* node, size_t buffer_size, uint worker_id) { + void apply_to_buffer(BufferNode* node, size_t buffer_capacity, uint worker_id) { void** buffer = BufferNode::make_buffer_from_node(node); - for (size_t i = node->index(); i < buffer_size; ++i) { + for (size_t i = node->index(); i < buffer_capacity; ++i) { CardValue* card_ptr = static_cast(buffer[i]); do_card_ptr(card_ptr, worker_id); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -87,7 +87,7 @@ void G1DirtyCardQueueSet::flush_queue(G1DirtyCardQueue& queue) { if (queue.buffer() != nullptr) { G1ConcurrentRefineStats* stats = queue.refinement_stats(); - stats->inc_dirtied_cards(buffer_size() - queue.index()); + stats->inc_dirtied_cards(buffer_capacity() - queue.index()); } PtrQueueSet::flush_queue(queue); } @@ -106,7 +106,7 @@ BufferNode* old_node = exchange_buffer_with_new(queue); if (old_node != nullptr) { G1ConcurrentRefineStats* stats = queue.refinement_stats(); - stats->inc_dirtied_cards(buffer_size()); + stats->inc_dirtied_cards(buffer_capacity()); handle_completed_buffer(old_node, stats); } } @@ -124,7 +124,7 @@ assert(cbn != nullptr, "precondition"); // Increment _num_cards before adding to queue, so queue removal doesn't // need to deal with _num_cards possibly going negative. - Atomic::add(&_num_cards, buffer_size() - cbn->index()); + Atomic::add(&_num_cards, buffer_capacity() - cbn->index()); // Perform push in CS. The old tail may be popped while the push is // observing it (attaching it to the new buffer). We need to ensure it // can't be reused until the push completes, to avoid ABA problems. @@ -160,7 +160,7 @@ result = dequeue_completed_buffer(); if (result == nullptr) return nullptr; } - Atomic::sub(&_num_cards, buffer_size() - result->index()); + Atomic::sub(&_num_cards, buffer_capacity() - result->index()); return result; } @@ -170,7 +170,7 @@ for (BufferNode* cur = _completed.first(); !_completed.is_end(cur); cur = cur->next()) { - actual += buffer_size() - cur->index(); + actual += buffer_capacity() - cur->index(); } assert(actual == Atomic::load(&_num_cards), "Num entries in completed buffers should be " SIZE_FORMAT " but are " SIZE_FORMAT, @@ -286,7 +286,7 @@ // notification checking after the coming safepoint if it doesn't GC. // Note that this means the queue's _num_cards differs from the number // of cards in the queued buffers when there are paused buffers. - Atomic::add(&_num_cards, buffer_size() - node->index()); + Atomic::add(&_num_cards, buffer_capacity() - node->index()); _paused.add(node); } @@ -342,30 +342,30 @@ class G1RefineBufferedCards : public StackObj { BufferNode* const _node; CardTable::CardValue** const _node_buffer; - const size_t _node_buffer_size; + const size_t _node_buffer_capacity; const uint _worker_id; G1ConcurrentRefineStats* _stats; G1RemSet* const _g1rs; - static inline int compare_card(const CardTable::CardValue* p1, - const CardTable::CardValue* p2) { + static inline ptrdiff_t compare_cards(const CardTable::CardValue* p1, + const CardTable::CardValue* p2) { return p2 - p1; } - // Sorts the cards from start_index to _node_buffer_size in *decreasing* + // Sorts the cards from start_index to _node_buffer_capacity in *decreasing* // address order. Tests showed that this order is preferable to not sorting // or increasing address order. void sort_cards(size_t start_index) { QuickSort::sort(&_node_buffer[start_index], - _node_buffer_size - start_index, - compare_card, + _node_buffer_capacity - start_index, + compare_cards, false); } // Returns the index to the first clean card in the buffer. size_t clean_cards() { const size_t start = _node->index(); - assert(start <= _node_buffer_size, "invariant"); + assert(start <= _node_buffer_capacity, "invariant"); // Two-fingered compaction algorithm similar to the filtering mechanism in // SATBMarkQueue. The main difference is that clean_card_before_refine() @@ -373,7 +373,7 @@ // We don't check for SuspendibleThreadSet::should_yield(), because // cleaning and redirtying the cards is fast. CardTable::CardValue** src = &_node_buffer[start]; - CardTable::CardValue** dst = &_node_buffer[_node_buffer_size]; + CardTable::CardValue** dst = &_node_buffer[_node_buffer_capacity]; assert(src <= dst, "invariant"); for ( ; src < dst; ++src) { // Search low to high for a card to keep. @@ -392,7 +392,7 @@ // dst points to the first retained clean card, or the end of the buffer // if all the cards were discarded. const size_t first_clean = dst - _node_buffer; - assert(first_clean >= start && first_clean <= _node_buffer_size, "invariant"); + assert(first_clean >= start && first_clean <= _node_buffer_capacity, "invariant"); // Discarded cards are considered as refined. _stats->inc_refined_cards(first_clean - start); _stats->inc_precleaned_cards(first_clean - start); @@ -402,7 +402,7 @@ bool refine_cleaned_cards(size_t start_index) { bool result = true; size_t i = start_index; - for ( ; i < _node_buffer_size; ++i) { + for ( ; i < _node_buffer_capacity; ++i) { if (SuspendibleThreadSet::should_yield()) { redirty_unrefined_cards(i); result = false; @@ -416,26 +416,26 @@ } void redirty_unrefined_cards(size_t start) { - for ( ; start < _node_buffer_size; ++start) { + for ( ; start < _node_buffer_capacity; ++start) { *_node_buffer[start] = G1CardTable::dirty_card_val(); } } public: G1RefineBufferedCards(BufferNode* node, - size_t node_buffer_size, + size_t node_buffer_capacity, uint worker_id, G1ConcurrentRefineStats* stats) : _node(node), _node_buffer(reinterpret_cast(BufferNode::make_buffer_from_node(node))), - _node_buffer_size(node_buffer_size), + _node_buffer_capacity(node_buffer_capacity), _worker_id(worker_id), _stats(stats), _g1rs(G1CollectedHeap::heap()->rem_set()) {} bool refine() { size_t first_clean_index = clean_cards(); - if (first_clean_index == _node_buffer_size) { + if (first_clean_index == _node_buffer_capacity) { _node->set_index(first_clean_index); return true; } @@ -458,7 +458,7 @@ G1ConcurrentRefineStats* stats) { Ticks start_time = Ticks::now(); G1RefineBufferedCards buffered_cards(node, - buffer_size(), + buffer_capacity(), worker_id, stats); bool result = buffered_cards.refine(); @@ -469,12 +469,12 @@ void G1DirtyCardQueueSet::handle_refined_buffer(BufferNode* node, bool fully_processed) { if (fully_processed) { - assert(node->index() == buffer_size(), + assert(node->index() == buffer_capacity(), "Buffer not fully consumed: index: " SIZE_FORMAT ", size: " SIZE_FORMAT, - node->index(), buffer_size()); + node->index(), buffer_capacity()); deallocate_buffer(node); } else { - assert(node->index() < buffer_size(), "Buffer fully consumed."); + assert(node->index() < buffer_capacity(), "Buffer fully consumed."); // Buffer incompletely processed because there is a pending safepoint. // Record partially processed buffer, to be finished later. record_paused_buffer(node); @@ -577,7 +577,7 @@ // Flush the buffer if non-empty. Flush before accumulating and // resetting stats, since flushing may modify the stats. if ((queue.buffer() != nullptr) && - (queue.index() != buffer_size())) { + (queue.index() != buffer_capacity())) { flush_queue(queue); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -195,7 +195,7 @@ void abandon_completed_buffers(); - // Refine the cards in "node" from its index to buffer_size. + // Refine the cards in "node" from its index to buffer_capacity. // Stops processing if SuspendibleThreadSet::should_yield() is true. // Returns true if the entire buffer was processed, false if there // is a pending yield request. The node's index is updated to exclude diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -374,7 +374,7 @@ } } -#define TIME_FORMAT "%.1lfms" +#define TIME_FORMAT "%.2lfms" void G1GCPhaseTimes::info_time(const char* name, double value) const { log_info(gc, phases)(" %s: " TIME_FORMAT, name, value); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1Policy.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1Policy.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1Policy.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1Policy.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -338,41 +338,47 @@ _reserve_regions, max_to_eat_into_reserve); + uint survivor_regions_count = _g1h->survivor_regions_count(); + uint desired_eden_length = desired_young_length - survivor_regions_count; + uint allocated_eden_length = allocated_young_length - survivor_regions_count; + if (_free_regions_at_end_of_collection <= _reserve_regions) { // Fully eat (or already eating) into the reserve, hand back at most absolute_min_length regions. - uint receiving_young = MIN3(_free_regions_at_end_of_collection, - desired_young_length, + uint receiving_eden = MIN3(_free_regions_at_end_of_collection, + desired_eden_length, max_to_eat_into_reserve); + // Ensure that we provision for at least one Eden region. + receiving_eden = MAX2(receiving_eden, 1u); // We could already have allocated more regions than what we could get // above. - receiving_additional_eden = allocated_young_length < receiving_young ? - receiving_young - allocated_young_length : 0; + receiving_additional_eden = allocated_eden_length < receiving_eden ? + receiving_eden - allocated_eden_length : 0; log_trace(gc, ergo, heap)("Young target length: Fully eat into reserve " - "receiving young %u receiving additional eden %u", - receiving_young, - receiving_additional_eden); - } else if (_free_regions_at_end_of_collection < (desired_young_length + _reserve_regions)) { + "receiving eden %u receiving additional eden %u", + receiving_eden, receiving_additional_eden); + } else if (_free_regions_at_end_of_collection < (desired_eden_length + _reserve_regions)) { // Partially eat into the reserve, at most max_to_eat_into_reserve regions. uint free_outside_reserve = _free_regions_at_end_of_collection - _reserve_regions; - assert(free_outside_reserve < desired_young_length, + assert(free_outside_reserve < desired_eden_length, "must be %u %u", - free_outside_reserve, desired_young_length); + free_outside_reserve, desired_eden_length); - uint receiving_within_reserve = MIN2(desired_young_length - free_outside_reserve, + uint receiving_within_reserve = MIN2(desired_eden_length - free_outside_reserve, max_to_eat_into_reserve); - uint receiving_young = free_outside_reserve + receiving_within_reserve; + uint receiving_eden = free_outside_reserve + receiving_within_reserve; + // Again, we could have already allocated more than we could get. - receiving_additional_eden = allocated_young_length < receiving_young ? - receiving_young - allocated_young_length : 0; + receiving_additional_eden = allocated_eden_length < receiving_eden ? + receiving_eden - allocated_eden_length : 0; log_trace(gc, ergo, heap)("Young target length: Partially eat into reserve " "free outside reserve %u " "receiving within reserve %u " - "receiving young %u " + "receiving eden %u " "receiving additional eden %u", free_outside_reserve, receiving_within_reserve, - receiving_young, receiving_additional_eden); + receiving_eden, receiving_additional_eden); } else { // No need to use the reserve. receiving_additional_eden = desired_young_length - allocated_young_length; diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -47,7 +47,7 @@ #endif // ASSERT void G1RedirtyCardsLocalQueueSet::enqueue_completed_buffer(BufferNode* node) { - _buffers._entry_count += buffer_size() - node->index(); + _buffers._entry_count += buffer_capacity() - node->index(); node->set_next(_buffers._head); _buffers._head = node; if (_buffers._tail == nullptr) { @@ -131,7 +131,7 @@ void G1RedirtyCardsQueueSet::enqueue_completed_buffer(BufferNode* node) { assert(_collecting, "precondition"); - Atomic::add(&_entry_count, buffer_size() - node->index()); + Atomic::add(&_entry_count, buffer_capacity() - node->index()); _list.push(*node); update_tail(node); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1RemSet.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1RemSet.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1RemSet.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1RemSet.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1283,9 +1283,9 @@ void apply_closure_to_dirty_card_buffers(G1MergeLogBufferCardsClosure* cl, uint worker_id) { G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); - size_t buffer_size = dcqs.buffer_size(); + size_t buffer_capacity = dcqs.buffer_capacity(); while (BufferNode* node = _dirty_card_buffers.pop()) { - cl->apply_to_buffer(node, buffer_size, worker_id); + cl->apply_to_buffer(node, buffer_capacity, worker_id); dcqs.deallocate_buffer(node); } } @@ -1588,7 +1588,7 @@ *card_ptr = G1CardTable::dirty_card_val(); G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); void** buffer = dcqs.allocate_buffer(); - size_t index = dcqs.buffer_size() - 1; + size_t index = dcqs.buffer_capacity() - 1; buffer[index] = card_ptr; dcqs.enqueue_completed_buffer(BufferNode::make_node_from_buffer(buffer, index)); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -398,13 +398,13 @@ void do_work(uint worker_id) override { RedirtyLoggedCardTableEntryClosure cl(G1CollectedHeap::heap(), _evac_failure_regions); - const size_t buffer_size = _rdcqs->buffer_size(); + const size_t buffer_capacity = _rdcqs->buffer_capacity(); BufferNode* next = Atomic::load(&_nodes); while (next != nullptr) { BufferNode* node = next; next = Atomic::cmpxchg(&_nodes, node, node->next()); if (next == node) { - cl.apply_to_buffer(node, buffer_size, worker_id); + cl.apply_to_buffer(node, buffer_capacity, worker_id); next = node->next(); } } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -167,11 +167,11 @@ ResourceMark rm; struct Verifier : public ThreadClosure { - size_t _buffer_size; - Verifier() : _buffer_size(G1BarrierSet::dirty_card_queue_set().buffer_size()) {} + size_t _buffer_capacity; + Verifier() : _buffer_capacity(G1BarrierSet::dirty_card_queue_set().buffer_capacity()) {} void do_thread(Thread* t) override { G1DirtyCardQueue& queue = G1ThreadLocalData::dirty_card_queue(t); - assert((queue.buffer() == nullptr) || (queue.index() == _buffer_size), + assert((queue.buffer() == nullptr) || (queue.index() == _buffer_capacity), "non-empty dirty card queue for thread %s", t->name()); } } verifier; diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/bufferNode.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/bufferNode.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/bufferNode.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/bufferNode.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -29,10 +29,10 @@ #include -BufferNode::AllocatorConfig::AllocatorConfig(size_t size) : _buffer_size(size) {} +BufferNode::AllocatorConfig::AllocatorConfig(size_t size) : _buffer_capacity(size) {} void* BufferNode::AllocatorConfig::allocate() { - size_t byte_size = _buffer_size * sizeof(void*); + size_t byte_size = _buffer_capacity * sizeof(void*); return NEW_C_HEAP_ARRAY(char, buffer_offset() + byte_size, mtGC); } @@ -41,8 +41,8 @@ FREE_C_HEAP_ARRAY(char, node); } -BufferNode::Allocator::Allocator(const char* name, size_t buffer_size) : - _config(buffer_size), +BufferNode::Allocator::Allocator(const char* name, size_t buffer_capacity) : + _config(buffer_capacity), _free_list(name, &_config) {} diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/bufferNode.hpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/bufferNode.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/bufferNode.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/bufferNode.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -78,7 +78,7 @@ // We use BufferNode::AllocatorConfig to set the allocation options for the // FreeListAllocator. class BufferNode::AllocatorConfig : public FreeListConfig { - const size_t _buffer_size; + const size_t _buffer_capacity; public: explicit AllocatorConfig(size_t size); @@ -88,7 +88,7 @@ void deallocate(void* node) override; - size_t buffer_size() const { return _buffer_size; } + size_t buffer_capacity() const { return _buffer_capacity; } }; class BufferNode::Allocator { @@ -100,10 +100,10 @@ NONCOPYABLE(Allocator); public: - Allocator(const char* name, size_t buffer_size); + Allocator(const char* name, size_t buffer_capacity); ~Allocator() = default; - size_t buffer_size() const { return _config.buffer_size(); } + size_t buffer_capacity() const { return _config.buffer_capacity(); } size_t free_count() const; BufferNode* allocate(); void release(BufferNode* node); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/gcArguments.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/gcArguments.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/gcArguments.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/gcArguments.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -30,6 +30,7 @@ #include "runtime/arguments.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" +#include "utilities/formatBuffer.hpp" #include "utilities/macros.hpp" size_t HeapAlignment = 0; @@ -170,6 +171,13 @@ FLAG_SET_ERGO(MinHeapDeltaBytes, align_up(MinHeapDeltaBytes, SpaceAlignment)); + if (checked_cast(ObjectAlignmentInBytes) > GCCardSizeInBytes) { + err_msg message("ObjectAlignmentInBytes %u is larger than GCCardSizeInBytes %u", + ObjectAlignmentInBytes, GCCardSizeInBytes); + vm_exit_during_initialization("Invalid combination of GCCardSizeInBytes and ObjectAlignmentInBytes", + message); + } + DEBUG_ONLY(assert_flags();) } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/locationPrinter.inline.hpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/locationPrinter.inline.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/locationPrinter.inline.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/locationPrinter.inline.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -27,6 +27,7 @@ #include "gc/shared/locationPrinter.hpp" +#include "memory/resourceArea.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oopsHierarchy.hpp" @@ -51,6 +52,7 @@ template bool BlockLocationPrinter::print_location(outputStream* st, void* addr) { + ResourceMark rm; // Check if addr points into Java heap. if (CollectedHeapT::heap()->is_in(addr)) { oop o = base_oop_or_null(addr); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/ptrQueue.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/ptrQueue.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/ptrQueue.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/ptrQueue.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -28,7 +28,7 @@ PtrQueue::PtrQueue(PtrQueueSet* qset) : _index(0), - _capacity_in_bytes(index_to_byte_index(qset->buffer_size())), + _capacity_in_bytes(index_to_byte_index(qset->buffer_capacity())), _buf(nullptr) {} @@ -37,7 +37,6 @@ } - PtrQueueSet::PtrQueueSet(BufferNode::Allocator* allocator) : _allocator(allocator) {} @@ -46,7 +45,7 @@ void PtrQueueSet::reset_queue(PtrQueue& queue) { if (queue.buffer() != nullptr) { - queue.set_index(buffer_size()); + queue.set_index(buffer_capacity()); } } @@ -57,7 +56,7 @@ queue.set_buffer(nullptr); queue.set_index(0); BufferNode* node = BufferNode::make_node_from_buffer(buffer, index); - if (index == buffer_size()) { + if (index == buffer_capacity()) { deallocate_buffer(node); } else { enqueue_completed_buffer(node); @@ -95,7 +94,7 @@ void PtrQueueSet::install_new_buffer(PtrQueue& queue) { queue.set_buffer(allocate_buffer()); - queue.set_index(buffer_size()); + queue.set_index(buffer_capacity()); } void** PtrQueueSet::allocate_buffer() { diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/ptrQueue.hpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/ptrQueue.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/ptrQueue.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/ptrQueue.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -155,11 +155,11 @@ // Return the associated BufferNode allocator. BufferNode::Allocator* allocator() const { return _allocator; } - // Return the buffer for a BufferNode of size buffer_size(). + // Return the buffer for a BufferNode of size buffer_capacity(). void** allocate_buffer(); // Return an empty buffer to the free list. The node is required - // to have been allocated with a size of buffer_size(). + // to have been allocated with a size of buffer_capacity(). void deallocate_buffer(BufferNode* node); // A completed buffer is a buffer the mutator is finished with, and @@ -168,8 +168,8 @@ // Adds node to the completed buffer list. virtual void enqueue_completed_buffer(BufferNode* node) = 0; - size_t buffer_size() const { - return _allocator->buffer_size(); + size_t buffer_capacity() const { + return _allocator->buffer_capacity(); } }; diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/satbMarkQueue.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/satbMarkQueue.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/satbMarkQueue.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/satbMarkQueue.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -124,7 +124,7 @@ void SATBMarkQueueSet::set_buffer_enqueue_threshold_percentage(uint value) { // Minimum threshold of 1 ensures enqueuing of completely full buffers. - size_t size = buffer_size(); + size_t size = buffer_capacity(); size_t enqueue_qty = (size * value) / 100; _buffer_enqueue_threshold = MAX2(size - enqueue_qty, (size_t)1); } @@ -194,9 +194,9 @@ virtual void do_thread(Thread* t) { SATBMarkQueue& queue = _qset->satb_queue_for_thread(t); if (queue.buffer() != nullptr) { - assert(!_active || queue.index() == _qset->buffer_size(), + assert(!_active || queue.index() == _qset->buffer_capacity(), "queues should be empty when activated"); - queue.set_index(_qset->buffer_size()); + queue.set_index(_qset->buffer_capacity()); } queue.set_active(_active); } @@ -209,7 +209,7 @@ if (nd != nullptr) { void **buf = BufferNode::make_buffer_from_node(nd); size_t index = nd->index(); - size_t size = buffer_size(); + size_t size = buffer_capacity(); assert(index <= size, "invariant"); cl->do_buffer(buf + index, size - index); deallocate_buffer(nd); @@ -255,9 +255,9 @@ // Ensure we'll enqueue completely full buffers. assert(threshold > 0, "enqueue threshold = 0"); // Ensure we won't enqueue empty buffers. - assert(threshold <= buffer_size(), + assert(threshold <= buffer_capacity(), "enqueue threshold %zu exceeds capacity %zu", - threshold, buffer_size()); + threshold, buffer_capacity()); return queue.index() < threshold; } @@ -310,7 +310,7 @@ while (nd != nullptr) { void** buf = BufferNode::make_buffer_from_node(nd); os::snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Enqueued: %d", i); - print_satb_buffer(buffer, buf, nd->index(), buffer_size()); + print_satb_buffer(buffer, buf, nd->index(), buffer_capacity()); nd = nd->next(); i += 1; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/satbMarkQueue.hpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/satbMarkQueue.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/satbMarkQueue.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/satbMarkQueue.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -181,7 +181,7 @@ // Two-fingered compaction toward the end. void** src = &buf[queue.index()]; - void** dst = &buf[buffer_size()]; + void** dst = &buf[buffer_capacity()]; assert(src <= dst, "invariant"); for ( ; src < dst; ++src) { // Search low to high for an entry to keep. diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/weakProcessorTimes.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/weakProcessorTimes.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/weakProcessorTimes.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/weakProcessorTimes.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -173,7 +173,7 @@ return indents[MIN2(i, max_indents_index)]; } -#define TIME_FORMAT "%.1lfms" +#define TIME_FORMAT "%.2lfms" void WeakProcessorTimes::log_summary(OopStorageSet::WeakId id, uint indent) const { LogTarget(Debug, gc, phases) lt; diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/workerDataArray.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/workerDataArray.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shared/workerDataArray.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shared/workerDataArray.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -36,11 +36,14 @@ return -1.0; } +#define WDA_TIME_FORMAT "%4.2lf" + template <> void WorkerDataArray::WDAPrinter::summary(outputStream* out, double min, double avg, double max, double diff, double sum, bool print_sum) { - out->print(" Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", min * MILLIUNITS, avg * MILLIUNITS, max * MILLIUNITS, diff* MILLIUNITS); + out->print(" Min: " WDA_TIME_FORMAT ", Avg: " WDA_TIME_FORMAT ", Max: " WDA_TIME_FORMAT ", Diff: " WDA_TIME_FORMAT, + min * MILLIUNITS, avg * MILLIUNITS, max * MILLIUNITS, diff* MILLIUNITS); if (print_sum) { - out->print(", Sum: %4.1lf", sum * MILLIUNITS); + out->print(", Sum: " WDA_TIME_FORMAT, sum * MILLIUNITS); } } @@ -58,7 +61,7 @@ for (uint i = 0; i < phase->_length; ++i) { double value = phase->get(i); if (value != phase->uninitialized()) { - out->print(" %4.1lf", phase->get(i) * 1000.0); + out->print(" " WDA_TIME_FORMAT, phase->get(i) * 1000.0); } else { out->print(" -"); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -639,6 +639,34 @@ } #endif +bool ShenandoahBarrierC2Support::is_anti_dependent_load_at_control(PhaseIdealLoop* phase, Node* maybe_load, Node* store, + Node* control) { + return maybe_load->is_Load() && phase->C->can_alias(store->adr_type(), phase->C->get_alias_index(maybe_load->adr_type())) && + phase->ctrl_or_self(maybe_load) == control; +} + +void ShenandoahBarrierC2Support::maybe_push_anti_dependent_loads(PhaseIdealLoop* phase, Node* maybe_store, Node* control, Unique_Node_List &wq) { + if (!maybe_store->is_Store() && !maybe_store->is_LoadStore()) { + return; + } + Node* mem = maybe_store->in(MemNode::Memory); + for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { + Node* u = mem->fast_out(i); + if (is_anti_dependent_load_at_control(phase, u, maybe_store, control)) { + wq.push(u); + } + } +} + +void ShenandoahBarrierC2Support::push_data_inputs_at_control(PhaseIdealLoop* phase, Node* n, Node* ctrl, Unique_Node_List &wq) { + for (uint i = 0; i < n->req(); i++) { + Node* in = n->in(i); + if (in != nullptr && (ShenandoahIUBarrier ? (phase->ctrl_or_self(in) == ctrl) : (phase->has_ctrl(in) && phase->get_ctrl(in) == ctrl))) { + wq.push(in); + } + } +} + bool ShenandoahBarrierC2Support::is_dominator_same_ctrl(Node* c, Node* d, Node* n, PhaseIdealLoop* phase) { // That both nodes have the same control is not sufficient to prove // domination, verify that there's no path from d to n @@ -653,22 +681,9 @@ if (m->is_Phi() && m->in(0)->is_Loop()) { assert(phase->ctrl_or_self(m->in(LoopNode::EntryControl)) != c, "following loop entry should lead to new control"); } else { - if (m->is_Store() || m->is_LoadStore()) { - // Take anti-dependencies into account - Node* mem = m->in(MemNode::Memory); - for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { - Node* u = mem->fast_out(i); - if (u->is_Load() && phase->C->can_alias(m->adr_type(), phase->C->get_alias_index(u->adr_type())) && - phase->ctrl_or_self(u) == c) { - wq.push(u); - } - } - } - for (uint i = 0; i < m->req(); i++) { - if (m->in(i) != nullptr && phase->ctrl_or_self(m->in(i)) == c) { - wq.push(m->in(i)); - } - } + // Take anti-dependencies into account + maybe_push_anti_dependent_loads(phase, m, c, wq); + push_data_inputs_at_control(phase, m, c, wq); } } return true; @@ -1020,7 +1035,20 @@ phase->register_new_node(val, ctrl); } -void ShenandoahBarrierC2Support::fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::collect_nodes_above_barrier(Unique_Node_List &nodes_above_barrier, PhaseIdealLoop* phase, Node* ctrl, Node* init_raw_mem) { + nodes_above_barrier.clear(); + if (phase->has_ctrl(init_raw_mem) && phase->get_ctrl(init_raw_mem) == ctrl && !init_raw_mem->is_Phi()) { + nodes_above_barrier.push(init_raw_mem); + } + for (uint next = 0; next < nodes_above_barrier.size(); next++) { + Node* n = nodes_above_barrier.at(next); + // Take anti-dependencies into account + maybe_push_anti_dependent_loads(phase, n, ctrl, nodes_above_barrier); + push_data_inputs_at_control(phase, n, ctrl, nodes_above_barrier); + } +} + +void ShenandoahBarrierC2Support::fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& nodes_above_barrier, uint last, PhaseIdealLoop* phase) { Node* ctrl = phase->get_ctrl(barrier); Node* init_raw_mem = fixer.find_mem(ctrl, barrier); @@ -1031,30 +1059,17 @@ // control will be after the expanded barrier. The raw memory (if // its memory is control dependent on the barrier's input control) // must stay above the barrier. - uses_to_ignore.clear(); - if (phase->has_ctrl(init_raw_mem) && phase->get_ctrl(init_raw_mem) == ctrl && !init_raw_mem->is_Phi()) { - uses_to_ignore.push(init_raw_mem); - } - for (uint next = 0; next < uses_to_ignore.size(); next++) { - Node *n = uses_to_ignore.at(next); - for (uint i = 0; i < n->req(); i++) { - Node* in = n->in(i); - if (in != nullptr && phase->has_ctrl(in) && phase->get_ctrl(in) == ctrl) { - uses_to_ignore.push(in); - } - } - } + collect_nodes_above_barrier(nodes_above_barrier, phase, ctrl, init_raw_mem); for (DUIterator_Fast imax, i = ctrl->fast_outs(imax); i < imax; i++) { Node* u = ctrl->fast_out(i); if (u->_idx < last && u != barrier && !u->depends_only_on_test() && // preserve dependency on test - !uses_to_ignore.member(u) && + !nodes_above_barrier.member(u) && (u->in(0) != ctrl || (!u->is_Region() && !u->is_Phi())) && (ctrl->Opcode() != Op_CatchProj || u->Opcode() != Op_CreateEx)) { Node* old_c = phase->ctrl_or_self(u); - Node* c = old_c; - if (c != ctrl || + if (old_c != ctrl || is_dominator_same_ctrl(old_c, barrier, u, phase) || ShenandoahBarrierSetC2::is_shenandoah_state_load(u)) { phase->igvn().rehash_node_delayed(u); @@ -1170,8 +1185,9 @@ } } } + // Load barrier on the control output of a call if ((ctrl->is_Proj() && ctrl->in(0)->is_CallJava()) || ctrl->is_CallJava()) { - CallNode* call = ctrl->is_Proj() ? ctrl->in(0)->as_CallJava() : ctrl->as_CallJava(); + CallJavaNode* call = ctrl->is_Proj() ? ctrl->in(0)->as_CallJava() : ctrl->as_CallJava(); if (call->entry_point() == OptoRuntime::rethrow_stub()) { // The rethrow call may have too many projections to be // properly handled here. Given there's no reason for a @@ -1207,6 +1223,14 @@ CallProjections projs; call->extract_projections(&projs, false, false); + // If this is a runtime call, it doesn't have an exception handling path + if (projs.fallthrough_catchproj == nullptr) { + assert(call->method() == nullptr, "should be runtime call"); + assert(projs.catchall_catchproj == nullptr, "runtime call should not have catch all projection"); + continue; + } + + // Otherwise, clone the barrier so there's one for the fallthrough and one for the exception handling path #ifdef ASSERT VectorSet cloned; #endif @@ -1334,7 +1358,7 @@ // Expand load-reference-barriers MemoryGraphFixer fixer(Compile::AliasIdxRaw, true, phase); - Unique_Node_List uses_to_ignore; + Unique_Node_List nodes_above_barriers; for (int i = state->load_reference_barriers_count() - 1; i >= 0; i--) { ShenandoahLoadReferenceBarrierNode* lrb = state->load_reference_barrier(i); uint last = phase->C->unique(); @@ -1429,7 +1453,7 @@ Node* out_val = val_phi; phase->register_new_node(val_phi, region); - fix_ctrl(lrb, region, fixer, uses, uses_to_ignore, last, phase); + fix_ctrl(lrb, region, fixer, uses, nodes_above_barriers, last, phase); ctrl = orig_ctrl; @@ -1585,7 +1609,7 @@ phase->register_control(region, loop, heap_stable_ctrl->in(0)); phase->register_new_node(phi, region); - fix_ctrl(barrier, region, fixer, uses, uses_to_ignore, last, phase); + fix_ctrl(barrier, region, fixer, uses, nodes_above_barriers, last, phase); for(uint next = 0; next < uses.size(); next++ ) { Node *n = uses.at(next); assert(phase->get_ctrl(n) == init_ctrl, "bad control"); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp openjdk-21-21.0.9+10/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -62,12 +62,16 @@ PhaseIdealLoop* phase, int flags); static void call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, DecoratorSet decorators, PhaseIdealLoop* phase); + + static void collect_nodes_above_barrier(Unique_Node_List &nodes_above_barrier, PhaseIdealLoop* phase, Node* ctrl, + Node* init_raw_mem); + static void test_in_cset(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase); static void move_gc_state_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase); static void merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase); static bool merge_point_safe(Node* region); static bool identical_backtoback_ifs(Node *n, PhaseIdealLoop* phase); - static void fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase); + static void fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& nodes_above_barrier, uint last, PhaseIdealLoop* phase); static IfNode* find_unswitching_candidate(const IdealLoopTree *loop, PhaseIdealLoop* phase); static Node* get_load_addr(PhaseIdealLoop* phase, VectorSet& visited, Node* lrb); @@ -82,6 +86,11 @@ static void pin_and_expand(PhaseIdealLoop* phase); static void optimize_after_expansion(VectorSet& visited, Node_Stack& nstack, Node_List& old_new, PhaseIdealLoop* phase); + static void push_data_inputs_at_control(PhaseIdealLoop* phase, Node* n, Node* ctrl, + Unique_Node_List &wq); + static bool is_anti_dependent_load_at_control(PhaseIdealLoop* phase, Node* maybe_load, Node* store, Node* control); + + static void maybe_push_anti_dependent_loads(PhaseIdealLoop* phase, Node* maybe_store, Node* control, Unique_Node_List &wq); #ifdef ASSERT static void verify(RootNode* root); #endif diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/include/jvm.h openjdk-21-21.0.9+10/src/hotspot/share/include/jvm.h --- openjdk-21-21.0.8+9/src/hotspot/share/include/jvm.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/include/jvm.h 2025-10-13 07:49:24.000000000 +0000 @@ -150,6 +150,9 @@ JNIEXPORT jboolean JNICALL JVM_IsUseContainerSupport(void); +JNIEXPORT jboolean JNICALL +JVM_IsContainerized(void); + JNIEXPORT void * JNICALL JVM_LoadZipLibrary(); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/interpreter/bytecodeStream.hpp openjdk-21-21.0.9+10/src/hotspot/share/interpreter/bytecodeStream.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/interpreter/bytecodeStream.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/interpreter/bytecodeStream.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -100,8 +100,23 @@ void set_next_bci(int bci) { assert(0 <= bci && bci <= method()->code_size(), "illegal bci"); _next_bci = bci; } // Bytecode-specific attributes - int dest() const { return bci() + bytecode().get_offset_s2(raw_code()); } - int dest_w() const { return bci() + bytecode().get_offset_s4(raw_code()); } + int get_offset_s2() const { return bytecode().get_offset_s2(raw_code()); } + int get_offset_s4() const { return bytecode().get_offset_s4(raw_code()); } + + // These methods are not safe to use before or during verification as they may + // have large offsets and cause overflows + int dest() const { + int min_offset = -1 * max_method_code_size; + int offset = bytecode().get_offset_s2(raw_code()); + guarantee(offset >= min_offset && offset <= max_method_code_size, "must be"); + return bci() + offset; + } + int dest_w() const { + int min_offset = -1 * max_method_code_size; + int offset = bytecode().get_offset_s4(raw_code()); + guarantee(offset >= min_offset && offset <= max_method_code_size, "must be"); + return bci() + offset; + } // One-byte indices. int get_index_u1() const { assert_raw_index_size(1); return *(jubyte*)(bcp()+1); } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/jfr/support/jfrSymbolTable.cpp openjdk-21-21.0.9+10/src/hotspot/share/jfr/support/jfrSymbolTable.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/jfr/support/jfrSymbolTable.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/jfr/support/jfrSymbolTable.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -23,11 +23,10 @@ */ #include "precompiled.hpp" -#include "classfile/javaClasses.inline.hpp" #include "classfile/classLoaderData.hpp" +#include "classfile/javaClasses.hpp" #include "jfr/support/jfrSymbolTable.hpp" -#include "oops/instanceKlass.hpp" -#include "oops/oop.inline.hpp" +#include "oops/klass.hpp" #include "oops/symbol.hpp" #include "runtime/mutexLocker.hpp" @@ -200,7 +199,7 @@ traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */) { assert(sym != nullptr, "invariant"); - return mark((uintptr_t)sym->identity_hash(), sym, leakp); + return mark(sym->identity_hash(), sym, leakp); } traceid JfrSymbolTable::mark(uintptr_t hash, const Symbol* sym, bool leakp) { @@ -236,59 +235,25 @@ } /* -* hidden classes symbol is the external name + -* the address of its InstanceKlass slash appended: -* java.lang.invoke.LambdaForm$BMH/22626602 -* -* caller needs ResourceMark -*/ - -uintptr_t JfrSymbolTable::hidden_klass_name_hash(const InstanceKlass* ik) { - assert(ik != nullptr, "invariant"); - assert(ik->is_hidden(), "invariant"); - const oop mirror = ik->java_mirror_no_keepalive(); - assert(mirror != nullptr, "invariant"); - return (uintptr_t)mirror->identity_hash(); -} - -static const char* create_hidden_klass_symbol(const InstanceKlass* ik, uintptr_t hash) { - assert(ik != nullptr, "invariant"); - assert(ik->is_hidden(), "invariant"); - assert(hash != 0, "invariant"); - char* hidden_symbol = nullptr; - const oop mirror = ik->java_mirror_no_keepalive(); - assert(mirror != nullptr, "invariant"); - char hash_buf[40]; - os::snprintf_checked(hash_buf, sizeof(hash_buf), "/" UINTX_FORMAT, hash); - const size_t hash_len = strlen(hash_buf); - const size_t result_len = ik->name()->utf8_length(); - hidden_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); - ik->name()->as_klass_external_name(hidden_symbol, (int)result_len + 1); - assert(strlen(hidden_symbol) == result_len, "invariant"); - strcpy(hidden_symbol + result_len, hash_buf); - assert(strlen(hidden_symbol) == result_len + hash_len, "invariant"); - return hidden_symbol; -} - -bool JfrSymbolTable::is_hidden_klass(const Klass* k) { + * The hidden class symbol is the external name with the + * address of its Klass slash appended. + * + * "java.lang.invoke.LambdaForm$DMH/0x0000000037144c00" + * + * Caller needs ResourceMark. + */ +traceid JfrSymbolTable::mark_hidden_klass_name(const Klass* k, bool leakp) { assert(k != nullptr, "invariant"); - return k->is_instance_klass() && ((const InstanceKlass*)k)->is_hidden(); -} - -traceid JfrSymbolTable::mark_hidden_klass_name(const InstanceKlass* ik, bool leakp) { - assert(ik != nullptr, "invariant"); - assert(ik->is_hidden(), "invariant"); - const uintptr_t hash = hidden_klass_name_hash(ik); - const char* const hidden_symbol = create_hidden_klass_symbol(ik, hash); - return mark(hash, hidden_symbol, leakp); + assert(k->is_hidden(), "invariant"); + const uintptr_t hash = k->name()->identity_hash(); + return mark(hash, k->external_name(), leakp); } traceid JfrSymbolTable::mark(const Klass* k, bool leakp) { assert(k != nullptr, "invariant"); traceid symbol_id = 0; - if (is_hidden_klass(k)) { - assert(k->is_instance_klass(), "invariant"); - symbol_id = mark_hidden_klass_name((const InstanceKlass*)k, leakp); + if (k->is_hidden()) { + symbol_id = mark_hidden_klass_name(k, leakp); } else { Symbol* const sym = k->name(); if (sym != nullptr) { diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/jfr/support/jfrSymbolTable.hpp openjdk-21-21.0.9+10/src/hotspot/share/jfr/support/jfrSymbolTable.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/jfr/support/jfrSymbolTable.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/jfr/support/jfrSymbolTable.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -100,16 +100,13 @@ traceid mark(const Symbol* sym, bool leakp = false); traceid mark(const char* str, bool leakp = false); traceid mark(uintptr_t hash, const char* str, bool leakp); + traceid mark_hidden_klass_name(const Klass* k, bool leakp); traceid bootstrap_name(bool leakp); bool has_entries() const { return has_symbol_entries() || has_string_entries(); } bool has_symbol_entries() const { return _symbol_list != nullptr; } bool has_string_entries() const { return _string_list != nullptr; } - traceid mark_hidden_klass_name(const InstanceKlass* k, bool leakp); - bool is_hidden_klass(const Klass* k); - uintptr_t hidden_klass_name_hash(const InstanceKlass* ik); - // hashtable(s) callbacks void on_link(const SymbolEntry* entry); bool on_equals(uintptr_t hash, const SymbolEntry* entry); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/oops/cpCache.hpp openjdk-21-21.0.9+10/src/hotspot/share/oops/cpCache.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/oops/cpCache.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/oops/cpCache.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -444,7 +444,14 @@ Array* resolved_indy_entries() { return _resolved_indy_entries; } ResolvedIndyEntry* resolved_indy_entry_at(int index) const { return _resolved_indy_entries->adr_at(index); } - int resolved_indy_entries_length() const { return _resolved_indy_entries->length(); } + + int resolved_indy_entries_length() const { + if (_resolved_indy_entries == nullptr) { + return 0; + } + return _resolved_indy_entries->length(); + } + void print_resolved_indy_entries(outputStream* st) const { for (int i = 0; i < _resolved_indy_entries->length(); i++) { _resolved_indy_entries->at(i).print_on(st); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/opto/convertnode.cpp openjdk-21-21.0.9+10/src/hotspot/share/opto/convertnode.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/opto/convertnode.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/opto/convertnode.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -77,6 +77,11 @@ assert(false, "Unrecognized comparison for Conv2B: %s", NodeClassNames[in(1)->Opcode()]); } + // Skip the transformation if input is unexpected. + if (cmp == nullptr) { + return nullptr; + } + // Replace Conv2B with the cmove Node* bol = phase->transform(new BoolNode(cmp, BoolTest::eq)); return new CMoveINode(bol, phase->intcon(1), phase->intcon(0), TypeInt::BOOL); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/opto/loopnode.cpp openjdk-21-21.0.9+10/src/hotspot/share/opto/loopnode.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/opto/loopnode.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/opto/loopnode.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -701,14 +701,24 @@ // We can only use that safepoint if there's no side effect between the backedge and the safepoint. - // mm is used for book keeping + // mm is the memory state at the safepoint (when it's a MergeMem) + // no_side_effect_since_safepoint() goes over the memory state at the backedge. It resets the mm input for each + // component of the memory state it encounters so it points to the base memory. Once no_side_effect_since_safepoint() + // is done, if no side effect after the safepoint was found, mm should transform to the base memory: the states at + // the backedge and safepoint are the same so all components of the memory state at the safepoint should have been + // reset. MergeMemNode* mm = nullptr; #ifdef ASSERT if (mem->is_MergeMem()) { mm = mem->clone()->as_MergeMem(); _igvn._worklist.push(mm); for (MergeMemStream mms(mem->as_MergeMem()); mms.next_non_empty(); ) { - if (mms.alias_idx() != Compile::AliasIdxBot && loop != get_loop(ctrl_or_self(mms.memory()))) { + // Loop invariant memory state won't be reset by no_side_effect_since_safepoint(). Do it here. + // Escape Analysis can add state to mm that it doesn't add to the backedge memory Phis, breaking verification + // code that relies on mm. Clear that extra state here. + if (mms.alias_idx() != Compile::AliasIdxBot && + (loop != get_loop(ctrl_or_self(mms.memory())) || + (mms.adr_type()->isa_oop_ptr() && mms.adr_type()->is_known_instance()))) { mm->set_memory_at(mms.alias_idx(), mem->as_MergeMem()->base_memory()); } } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/opto/loopopts.cpp openjdk-21-21.0.9+10/src/hotspot/share/opto/loopopts.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/opto/loopopts.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/opto/loopopts.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1849,10 +1849,11 @@ // Sinking a node from a pre loop to its main loop pins the node between the pre and main loops. If that node is input // to a check that's eliminated by range check elimination, it becomes input to an expression that feeds into the exit // test of the pre loop above the point in the graph where it's pinned. - if (n_loop->_head->is_CountedLoop() && n_loop->_head->as_CountedLoop()->is_pre_loop() && - u_loop->_head->is_CountedLoop() && u_loop->_head->as_CountedLoop()->is_main_loop() && - n_loop->_next == get_loop(u_loop->_head->as_CountedLoop()->skip_strip_mined())) { - return false; + if (n_loop->_head->is_CountedLoop() && n_loop->_head->as_CountedLoop()->is_pre_loop()) { + CountedLoopNode* pre_loop = n_loop->_head->as_CountedLoop(); + if (is_dominator(pre_loop->loopexit(), ctrl)) { + return false; + } } return true; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/opto/mulnode.cpp openjdk-21-21.0.9+10/src/hotspot/share/opto/mulnode.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/opto/mulnode.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/opto/mulnode.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -245,7 +245,7 @@ // Check for negative constant; if so negate the final result bool sign_flip = false; - unsigned int abs_con = uabs(con); + unsigned int abs_con = g_uabs(con); if (abs_con != (unsigned int)con) { sign_flip = true; } @@ -480,7 +480,7 @@ // Check for negative constant; if so negate the final result bool sign_flip = false; - julong abs_con = uabs(con); + julong abs_con = g_uabs(con); if (abs_con != (julong)con) { sign_flip = true; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/opto/reg_split.cpp openjdk-21-21.0.9+10/src/hotspot/share/opto/reg_split.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/opto/reg_split.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/opto/reg_split.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -503,7 +503,6 @@ uint bidx, pidx, slidx, insidx, inpidx, twoidx; uint non_phi = 1, spill_cnt = 0; Node *n1, *n2, *n3; - Node_List *defs,*phis; bool *UPblock; bool u1, u2, u3; Block *b, *pred; @@ -519,9 +518,6 @@ //----------Setup Code---------- // Create a convenient mapping from lrg numbers to reaches/leaves indices uint *lrg2reach = NEW_SPLIT_ARRAY(uint, maxlrg); - // Keep track of DEFS & Phis for later passes - defs = new Node_List(); - phis = new Node_List(); // Gather info on which LRG's are spilling, and build maps for (bidx = 1; bidx < maxlrg; bidx++) { if (lrgs(bidx).alive() && lrgs(bidx).reg() >= LRG::SPILL_REG) { @@ -569,8 +565,14 @@ #undef NEW_SPLIT_ARRAY // Initialize to array of empty vectorsets - for( slidx = 0; slidx < spill_cnt; slidx++ ) - UP_entry[slidx] = new VectorSet(split_arena); + // Each containing at most spill_cnt * _cfg.number_of_blocks() entries. + for (slidx = 0; slidx < spill_cnt; slidx++) { + UP_entry[slidx] = new(split_arena) VectorSet(split_arena); + } + + // Keep track of DEFS & Phis for later passes + Node_List defs(split_arena, 8); + Node_List phis(split_arena, 16); //----------PASS 1---------- //----------Propagation & Node Insertion Code---------- @@ -702,7 +704,7 @@ } // end if not found correct phi // Here you have either found or created the Phi, so record it assert(phi != nullptr,"Must have a Phi Node here"); - phis->push(phi); + phis.push(phi); // PhiNodes should either force the LRG UP or DOWN depending // on its inputs and the register pressure in the Phi's block. UPblock[slidx] = true; // Assume new DEF is UP @@ -1189,7 +1191,7 @@ if( deflrg.reg() >= LRG::SPILL_REG ) { // Spilled? uint slidx = lrg2reach[defidx]; // Add to defs list for later assignment of new live range number - defs->push(n); + defs.push(n); // Set a flag on the Node indicating it has already spilled. // Only do it for capacity spills not conflict spills. if( !deflrg._direct_conflict ) @@ -1308,9 +1310,9 @@ //----------PASS 2---------- // Reset all DEF live range numbers here - for( insidx = 0; insidx < defs->size(); insidx++ ) { + for( insidx = 0; insidx < defs.size(); insidx++ ) { // Grab the def - n1 = defs->at(insidx); + n1 = defs.at(insidx); // Set new lidx for DEF new_lrg(n1, maxlrg++); } @@ -1320,8 +1322,8 @@ // info for each spilled LRG and update edges. // Walk the phis list to patch inputs, split phis, and name phis uint lrgs_before_phi_split = maxlrg; - for( insidx = 0; insidx < phis->size(); insidx++ ) { - Node *phi = phis->at(insidx); + for( insidx = 0; insidx < phis.size(); insidx++ ) { + Node *phi = phis.at(insidx); assert(phi->is_Phi(),"This list must only contain Phi Nodes"); Block *b = _cfg.get_block_for_node(phi); // Grab the live range number @@ -1389,8 +1391,8 @@ //----------PASS 3---------- // Pass over all Phi's to union the live ranges - for( insidx = 0; insidx < phis->size(); insidx++ ) { - Node *phi = phis->at(insidx); + for( insidx = 0; insidx < phis.size(); insidx++ ) { + Node *phi = phis.at(insidx); assert(phi->is_Phi(),"This list must only contain Phi Nodes"); // Walk all inputs to Phi and Union input live range with Phi live range for( uint i = 1; i < phi->req(); i++ ) { @@ -1408,9 +1410,9 @@ } // End for all inputs to the Phi Node } // End for all Phi Nodes // Now union all two address instructions - for (insidx = 0; insidx < defs->size(); insidx++) { + for (insidx = 0; insidx < defs.size(); insidx++) { // Grab the def - n1 = defs->at(insidx); + n1 = defs.at(insidx); // Set new lidx for DEF & handle 2-addr instructions if (n1->is_Mach() && ((twoidx = n1->as_Mach()->two_adr()) != 0)) { assert(_lrg_map.find(n1->in(twoidx)) < maxlrg,"Assigning bad live range index"); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/opto/subnode.cpp openjdk-21-21.0.9+10/src/hotspot/share/opto/subnode.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/opto/subnode.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/opto/subnode.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1899,14 +1899,14 @@ case Type::Int: { const TypeInt* ti = t1->is_int(); if (ti->is_con()) { - return TypeInt::make(uabs(ti->get_con())); + return TypeInt::make(g_uabs(ti->get_con())); } break; } case Type::Long: { const TypeLong* tl = t1->is_long(); if (tl->is_con()) { - return TypeLong::make(uabs(tl->get_con())); + return TypeLong::make(g_uabs(tl->get_con())); } break; } diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/opto/type.cpp openjdk-21-21.0.9+10/src/hotspot/share/opto/type.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/opto/type.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/opto/type.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -3125,8 +3125,8 @@ return (TypeRawPtr*)(new TypeRawPtr(ptr,0))->hashcons(); } -const TypeRawPtr *TypeRawPtr::make( address bits ) { - assert( bits, "Use TypePtr for null" ); +const TypeRawPtr *TypeRawPtr::make(address bits) { + assert(bits != nullptr, "Use TypePtr for null"); return (TypeRawPtr*)(new TypeRawPtr(Constant,bits))->hashcons(); } @@ -3215,15 +3215,21 @@ case TypePtr::BotPTR: case TypePtr::NotNull: return this; - case TypePtr::Null: case TypePtr::Constant: { - address bits = _bits+offset; - if ( bits == 0 ) return TypePtr::NULL_PTR; - return make( bits ); + uintptr_t bits = (uintptr_t)_bits; + uintptr_t sum = bits + offset; + if (( offset < 0 ) + ? ( sum > bits ) // Underflow? + : ( sum < bits )) { // Overflow? + return BOTTOM; + } else if ( sum == 0 ) { + return TypePtr::NULL_PTR; + } else { + return make( (address)sum ); + } } default: ShouldNotReachHere(); } - return nullptr; // Lint noise } //------------------------------eq--------------------------------------------- diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/prims/jvm.cpp openjdk-21-21.0.9+10/src/hotspot/share/prims/jvm.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/prims/jvm.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/prims/jvm.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -110,6 +110,9 @@ #if INCLUDE_MANAGEMENT #include "services/finalizerService.hpp" #endif +#ifdef LINUX +#include "osContainer_linux.hpp" +#endif #include @@ -493,6 +496,15 @@ return JNI_FALSE; JVM_END +JVM_LEAF(jboolean, JVM_IsContainerized(void)) +#ifdef LINUX + if (OSContainer::is_containerized()) { + return JNI_TRUE; + } +#endif + return JNI_FALSE; +JVM_END + // java.lang.Throwable ////////////////////////////////////////////////////// JVM_ENTRY(void, JVM_FillInStackTrace(JNIEnv *env, jobject receiver)) @@ -2955,9 +2967,10 @@ // We must release the Threads_lock before we can post a jvmti event // in Thread::start. { + MutexLocker throttle_ml(UseThreadsLockThrottleLock ? ThreadsLockThrottle_lock : nullptr); // Ensure that the C++ Thread and OSThread structures aren't freed before // we operate. - MutexLocker mu(Threads_lock); + MutexLocker ml(Threads_lock); // Since JDK 5 the java.lang.Thread threadStatus is used to prevent // re-starting an already started thread, so we should usually find diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/prims/methodHandles.cpp openjdk-21-21.0.9+10/src/hotspot/share/prims/methodHandles.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/prims/methodHandles.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/prims/methodHandles.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -934,19 +934,12 @@ void MethodHandles::add_dependent_nmethod(oop call_site, nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); - oop context = java_lang_invoke_CallSite::context_no_keepalive(call_site); - DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); - // Try to purge stale entries on updates. - // Since GC doesn't clean dependency contexts rooted at CallSiteContext objects, - // in order to avoid memory leak, stale entries are purged whenever a dependency list - // is changed (both on addition and removal). Though memory reclamation is delayed, - // it avoids indefinite memory usage growth. + DependencyContext deps = java_lang_invoke_CallSite::vmdependencies(call_site); deps.add_dependent_nmethod(nm); } void MethodHandles::clean_dependency_context(oop call_site) { - oop context = java_lang_invoke_CallSite::context_no_keepalive(call_site); - DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); + DependencyContext deps = java_lang_invoke_CallSite::vmdependencies(call_site); deps.clean_unloading_dependents(); } @@ -958,8 +951,7 @@ NoSafepointVerifier nsv; MutexLocker ml(CodeCache_lock, Mutex::_no_safepoint_check_flag); - oop context = java_lang_invoke_CallSite::context_no_keepalive(call_site()); - DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); + DependencyContext deps = java_lang_invoke_CallSite::vmdependencies(call_site()); deps.mark_dependent_nmethods(deopt_scope, changes); } } @@ -1323,23 +1315,6 @@ } JVM_END -// It is called by a Cleaner object which ensures that dropped CallSites properly -// deallocate their dependency information. -JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject context_jh)) { - Handle context(THREAD, JNIHandles::resolve_non_null(context_jh)); - DeoptimizationScope deopt_scope; - { - NoSafepointVerifier nsv; - MutexLocker ml(THREAD, CodeCache_lock, Mutex::_no_safepoint_check_flag); - DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context()); - deps.remove_and_mark_for_deoptimization_all_dependents(&deopt_scope); - // This is assumed to be an 'atomic' operation by verification. - // So keep it under lock for now. - deopt_scope.deoptimize_marked(); - } -} -JVM_END - /** * Throws a java/lang/UnsupportedOperationException unconditionally. * This is required by the specification of MethodHandle.invoke if @@ -1374,7 +1349,6 @@ #define MT JLINV "MethodType;" #define MH JLINV "MethodHandle;" #define MEM JLINV "MemberName;" -#define CTX JLINV "MethodHandleNatives$CallSiteContext;" #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) @@ -1390,7 +1364,6 @@ {CC "setCallSiteTargetNormal", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetNormal)}, {CC "setCallSiteTargetVolatile", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetVolatile)}, {CC "copyOutBootstrapArguments", CC "(" CLS "[III[" OBJ "IZ" OBJ ")V", FN_PTR(MHN_copyOutBootstrapArguments)}, - {CC "clearCallSiteContext", CC "(" CTX ")V", FN_PTR(MHN_clearCallSiteContext)}, {CC "staticFieldOffset", CC "(" MEM ")J", FN_PTR(MHN_staticFieldOffset)}, {CC "staticFieldBase", CC "(" MEM ")" OBJ, FN_PTR(MHN_staticFieldBase)}, {CC "getMemberVMInfo", CC "(" MEM ")" OBJ, FN_PTR(MHN_getMemberVMInfo)} diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/prims/whitebox.cpp openjdk-21-21.0.9+10/src/hotspot/share/prims/whitebox.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/prims/whitebox.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/prims/whitebox.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1049,6 +1049,22 @@ } #endif +bool WhiteBox::is_asan_enabled() { +#ifdef ADDRESS_SANITIZER + return true; +#else + return false; +#endif +} + +bool WhiteBox::is_ubsan_enabled() { +#ifdef UNDEFINED_BEHAVIOR_SANITIZER + return true; +#else + return false; +#endif +} + bool WhiteBox::compile_method(Method* method, int comp_level, int bci, JavaThread* THREAD) { // Screen for unavailable/bad comp level or null method AbstractCompiler* comp = CompileBroker::compiler(comp_level); @@ -1832,6 +1848,14 @@ return (jboolean) obj_oop->mark().has_monitor(); WB_END +WB_ENTRY(jboolean, WB_IsAsanEnabled(JNIEnv* env)) + return (jboolean) WhiteBox::is_asan_enabled(); +WB_END + +WB_ENTRY(jboolean, WB_IsUbsanEnabled(JNIEnv* env)) + return (jboolean) WhiteBox::is_ubsan_enabled(); +WB_END + WB_ENTRY(jboolean, WB_DeflateIdleMonitors(JNIEnv* env, jobject wb)) log_info(monitorinflation)("WhiteBox initiated DeflateIdleMonitors"); return ObjectSynchronizer::request_deflate_idle_monitors_from_wb(); @@ -2418,6 +2442,13 @@ return ret; WB_END +// Available cpus of the host machine, Linux only. +// Used in container testing. +WB_ENTRY(jint, WB_HostCPUs(JNIEnv* env, jobject o)) + LINUX_ONLY(return os::Linux::active_processor_count();) + return -1; // Not used/implemented on other platforms +WB_END + WB_ENTRY(void, WB_PrintOsInfo(JNIEnv* env, jobject o)) os::print_os_info(tty); WB_END @@ -2751,6 +2782,8 @@ (void*)&WB_AddModuleExportsToAll }, {CC"deflateIdleMonitors", CC"()Z", (void*)&WB_DeflateIdleMonitors }, {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, + {CC"isAsanEnabled", CC"()Z", (void*)&WB_IsAsanEnabled }, + {CC"isUbsanEnabled", CC"()Z", (void*)&WB_IsUbsanEnabled }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, {CC"forceClassLoaderStatsSafepoint", CC"()V", (void*)&WB_ForceClassLoaderStatsSafepoint }, {CC"getConstantPool0", CC"(Ljava/lang/Class;)J", (void*)&WB_GetConstantPool }, @@ -2824,6 +2857,7 @@ (void*)&WB_ValidateCgroup }, {CC"hostPhysicalMemory", CC"()J", (void*)&WB_HostPhysicalMemory }, {CC"hostPhysicalSwap", CC"()J", (void*)&WB_HostPhysicalSwap }, + {CC"hostCPUs", CC"()I", (void*)&WB_HostCPUs }, {CC"printOsInfo", CC"()V", (void*)&WB_PrintOsInfo }, {CC"disableElfSectionCache", CC"()V", (void*)&WB_DisableElfSectionCache }, {CC"resolvedMethodItemsCount", CC"()J", (void*)&WB_ResolvedMethodItemsCount }, diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/prims/whitebox.hpp openjdk-21-21.0.9+10/src/hotspot/share/prims/whitebox.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/prims/whitebox.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/prims/whitebox.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -71,6 +71,9 @@ #ifdef LINUX static bool validate_cgroup(const char* proc_cgroups, const char* proc_self_cgroup, const char* proc_self_mountinfo, u1* cg_flags); #endif + // provide info about enabling of Address Sanitizer / Undefined Behavior Sanitizer + static bool is_asan_enabled(); + static bool is_ubsan_enabled(); }; #endif // SHARE_PRIMS_WHITEBOX_HPP diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/runtime/globals.hpp openjdk-21-21.0.9+10/src/hotspot/share/runtime/globals.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/runtime/globals.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/runtime/globals.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1990,6 +1990,10 @@ "(default) disables native heap trimming.") \ range(0, UINT_MAX) \ \ + product(bool, UseThreadsLockThrottleLock, true, DIAGNOSTIC, \ + "Use an extra lock during Thread start and exit to alleviate" \ + "contention on Threads_lock.") \ + \ product(bool, UseSecondarySupersCache, true, DIAGNOSTIC, \ "Use secondary supers cache during subtype checks.") \ \ diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/runtime/mutexLocker.cpp openjdk-21-21.0.9+10/src/hotspot/share/runtime/mutexLocker.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/runtime/mutexLocker.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/runtime/mutexLocker.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -66,6 +66,7 @@ Mutex* TouchedMethodLog_lock = nullptr; Mutex* RetData_lock = nullptr; Monitor* VMOperation_lock = nullptr; +Monitor* ThreadsLockThrottle_lock = nullptr; Monitor* Threads_lock = nullptr; Mutex* NonJavaThreadsList_lock = nullptr; Mutex* NonJavaThreadsListSync_lock = nullptr; @@ -326,6 +327,8 @@ MUTEX_DEFN(JVMCIRuntime_lock , PaddedMonitor, safepoint, true); #endif + MUTEX_DEFN(ThreadsLockThrottle_lock , PaddedMonitor, safepoint); + // These locks have relative rankings, and inherit safepoint checking attributes from that rank. MUTEX_DEFL(InlineCacheBuffer_lock , PaddedMutex , CompiledIC_lock); MUTEX_DEFL(VtableStubs_lock , PaddedMutex , CompiledIC_lock); // Also holds DumpTimeTable_lock diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/runtime/mutexLocker.hpp openjdk-21-21.0.9+10/src/hotspot/share/runtime/mutexLocker.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/runtime/mutexLocker.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/runtime/mutexLocker.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -61,6 +61,8 @@ extern Mutex* TouchedMethodLog_lock; // a lock on allocation of LogExecutedMethods info extern Mutex* RetData_lock; // a lock on installation of RetData inside method data extern Monitor* VMOperation_lock; // a lock on queue of vm_operations waiting to execute +extern Monitor* ThreadsLockThrottle_lock; // used by Thread start/exit to reduce competition for Threads_lock, + // so a VM thread calling a safepoint is prioritized extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads // (also used by Safepoints too to block threads creation/destruction) extern Mutex* NonJavaThreadsList_lock; // a lock on the NonJavaThreads list diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/runtime/os.cpp openjdk-21-21.0.9+10/src/hotspot/share/runtime/os.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/runtime/os.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/runtime/os.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1472,6 +1472,56 @@ return false; } +static char* _image_release_file_content = nullptr; + +void os::read_image_release_file() { + assert(_image_release_file_content == nullptr, "release file content must not be already set"); + const char* home = Arguments::get_java_home(); + stringStream ss; + ss.print("%s/release", home); + + FILE* file = fopen(ss.base(), "rb"); + if (file == nullptr) { + return; + } + fseek(file, 0, SEEK_END); + long sz = ftell(file); + if (sz == -1) { + return; + } + fseek(file, 0, SEEK_SET); + + char* tmp = (char*) os::malloc(sz + 1, mtInternal); + if (tmp == nullptr) { + fclose(file); + return; + } + + size_t elements_read = fread(tmp, 1, sz, file); + if (elements_read < (size_t)sz) { + tmp[elements_read] = '\0'; + } else { + tmp[sz] = '\0'; + } + // issues with \r in line endings on Windows, so better replace those + for (size_t i = 0; i < elements_read; i++) { + if (tmp[i] == '\r') { + tmp[i] = ' '; + } + } + Atomic::release_store(&_image_release_file_content, tmp); + fclose(file); +} + +void os::print_image_release_file(outputStream* st) { + char* ifrc = Atomic::load_acquire(&_image_release_file_content); + if (ifrc != nullptr) { + st->print_cr("%s", ifrc); + } else { + st->print_cr(""); + } +} + bool os::file_exists(const char* filename) { struct stat statbuf; if (filename == nullptr || strlen(filename) == 0) { diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/runtime/os.hpp openjdk-21-21.0.9+10/src/hotspot/share/runtime/os.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/runtime/os.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/runtime/os.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -640,6 +640,11 @@ static FILE* fopen(const char* path, const char* mode); static jlong lseek(int fd, jlong offset, int whence); static bool file_exists(const char* file); + + // read/store and print the release file of the image + static void read_image_release_file(); + static void print_image_release_file(outputStream* st); + // This function, on Windows, canonicalizes a given path (see os_windows.cpp for details). // On Posix, this function is a noop: it does not change anything and just returns // the input pointer. diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/runtime/threads.cpp openjdk-21-21.0.9+10/src/hotspot/share/runtime/threads.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/runtime/threads.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/runtime/threads.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -408,6 +408,19 @@ initialize_class(vmSymbols::java_lang_invoke_MethodHandleNatives(), CHECK); } +// One-shot PeriodicTask subclass for reading the release file +class ReadReleaseFileTask : public PeriodicTask { + public: + ReadReleaseFileTask() : PeriodicTask(100) {} + + virtual void task() { + os::read_image_release_file(); + + // Reclaim our storage and disenroll ourself. + delete this; + } +}; + jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { extern void JDK_Version_init(); @@ -555,6 +568,10 @@ return status; } + // Have the WatcherThread read the release file in the background. + ReadReleaseFileTask* read_task = new ReadReleaseFileTask(); + read_task->enroll(); + // Create WatcherThread as soon as we can since we need it in case // of hangs during error reporting. WatcherThread::start(); @@ -1017,7 +1034,9 @@ void Threads::remove(JavaThread* p, bool is_daemon) { // Extra scope needed for Thread_lock, so we can check // that we do not remove thread without safepoint code notice - { MonitorLocker ml(Threads_lock); + { + MutexLocker throttle_ml(UseThreadsLockThrottleLock ? ThreadsLockThrottle_lock : nullptr); + MonitorLocker ml(Threads_lock); if (ThreadIdTable::is_initialized()) { // This cleanup must be done before the current thread's GC barrier @@ -1065,7 +1084,7 @@ // Notify threads waiting in EscapeBarriers EscapeBarrier::thread_removed(p); - } // unlock Threads_lock + } // unlock Threads_lock and ThreadsLockThrottle_lock // Reduce the ObjectMonitor ceiling for the exiting thread. ObjectSynchronizer::dec_in_use_list_ceiling(); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/sanitizers/ub.hpp openjdk-21-21.0.9+10/src/hotspot/share/sanitizers/ub.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/sanitizers/ub.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/sanitizers/ub.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2024 SAP SE. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025 SAP SE. 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 @@ -33,7 +33,10 @@ // Useful if the function or method is known to do something special or even 'dangerous', for // example causing desired signals/crashes. #ifdef UNDEFINED_BEHAVIOR_SANITIZER -#if defined(__clang__) || defined(__GNUC__) +#if defined(__clang__) +#define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined","float-divide-by-zero"))) +#endif +#if defined(__GNUC__) && !defined(__clang__) #define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) #endif #endif diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/services/memReporter.cpp openjdk-21-21.0.9+10/src/hotspot/share/services/memReporter.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/services/memReporter.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/services/memReporter.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -516,8 +516,9 @@ const char* scale = current_scale(); outputStream* out = output(); out->print("arena=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale); - if (diff_in_current_scale(current_amount, early_amount) != 0) { - out->print(" " INT64_PLUS_FORMAT "d", diff_in_current_scale(current_amount, early_amount)); + int64_t amount_diff = diff_in_current_scale(current_amount, early_amount); + if (amount_diff != 0) { + out->print(" " INT64_PLUS_FORMAT "%s", amount_diff, scale); } out->print(" #" SIZE_FORMAT "", current_count); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/utilities/globalDefinitions.hpp openjdk-21-21.0.9+10/src/hotspot/share/utilities/globalDefinitions.hpp --- openjdk-21-21.0.8+9/src/hotspot/share/utilities/globalDefinitions.hpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/utilities/globalDefinitions.hpp 2025-10-13 07:49:24.000000000 +0000 @@ -1164,7 +1164,7 @@ // abs methods which cannot overflow and so are well-defined across // the entire domain of integer types. -static inline unsigned int uabs(unsigned int n) { +static inline unsigned int g_uabs(unsigned int n) { union { unsigned int result; int value; @@ -1173,7 +1173,7 @@ if (value < 0) result = 0-result; return result; } -static inline julong uabs(julong n) { +static inline julong g_uabs(julong n) { union { julong result; jlong value; @@ -1182,8 +1182,8 @@ if (value < 0) result = 0-result; return result; } -static inline julong uabs(jlong n) { return uabs((julong)n); } -static inline unsigned int uabs(int n) { return uabs((unsigned int)n); } +static inline julong g_uabs(jlong n) { return g_uabs((julong)n); } +static inline unsigned int g_uabs(int n) { return g_uabs((unsigned int)n); } // "to" should be greater than "from." inline intx byte_size(void* from, void* to) { diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/utilities/spinYield.cpp openjdk-21-21.0.9+10/src/hotspot/share/utilities/spinYield.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/utilities/spinYield.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/utilities/spinYield.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -66,7 +66,7 @@ if (_sleep_time.value() != 0) { // Report sleep duration, if slept. separator = print_separator(s, separator); s->print("sleep = " UINT64_FORMAT " usecs", - _sleep_time.milliseconds()); + _sleep_time.microseconds()); } if (separator == initial_separator) { s->print("no waiting"); diff -Nru openjdk-21-21.0.8+9/src/hotspot/share/utilities/vmError.cpp openjdk-21-21.0.9+10/src/hotspot/share/utilities/vmError.cpp --- openjdk-21-21.0.8+9/src/hotspot/share/utilities/vmError.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/hotspot/share/utilities/vmError.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1291,6 +1291,10 @@ LogConfiguration::describe_current_configuration(st); st->cr(); + STEP_IF("printing release file content", _verbose) + st->print_cr("Release file:"); + os::print_image_release_file(st); + STEP_IF("printing all environment variables", _verbose) os::print_environment_variables(st, env_list); st->cr(); @@ -1466,6 +1470,10 @@ LogConfiguration::describe(st); st->cr(); + // STEP("printing release file content") + st->print_cr("Release file:"); + os::print_image_release_file(st); + // STEP("printing all environment variables") os::print_environment_variables(st, env_list); diff -Nru openjdk-21-21.0.8+9/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java openjdk-21-21.0.9+10/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java --- openjdk-21-21.0.8+9/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java 2025-10-13 07:49:24.000000000 +0000 @@ -36,6 +36,11 @@ } @Override + public boolean isContainerized() { + return isContainerized0(); + } + + @Override public String getProvider() { return subsystem.getProvider(); } @@ -194,6 +199,7 @@ } private static native boolean isUseContainerSupport(); + private static native boolean isContainerized0(); private static native long getTotalMemorySize0(); private static native long getTotalSwapSize0(); diff -Nru openjdk-21-21.0.8+9/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java openjdk-21-21.0.9+10/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java --- openjdk-21-21.0.8+9/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java 2025-10-13 07:49:24.000000000 +0000 @@ -31,6 +31,11 @@ */ public interface CgroupSubsystem extends Metrics { + + default boolean isContainerized() { + return false; // This default impl is never used + } + /** * Returned for metrics of type long if the underlying implementation * has determined that no limit is being imposed. diff -Nru openjdk-21-21.0.8+9/src/java.base/linux/native/libjava/CgroupMetrics.c openjdk-21-21.0.9+10/src/java.base/linux/native/libjava/CgroupMetrics.c --- openjdk-21-21.0.8+9/src/java.base/linux/native/libjava/CgroupMetrics.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/linux/native/libjava/CgroupMetrics.c 2025-10-13 07:49:24.000000000 +0000 @@ -36,6 +36,12 @@ return JVM_IsUseContainerSupport(); } +JNIEXPORT jboolean JNICALL +Java_jdk_internal_platform_CgroupMetrics_isContainerized0(JNIEnv *env, jclass ignored) +{ + return JVM_IsContainerized(); +} + JNIEXPORT jlong JNICALL Java_jdk_internal_platform_CgroupMetrics_getTotalMemorySize0 (JNIEnv *env, jclass ignored) diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/lang/AbstractStringBuilder.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/AbstractStringBuilder.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/lang/AbstractStringBuilder.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/AbstractStringBuilder.java 2025-10-13 07:49:24.000000000 +0000 @@ -1313,8 +1313,8 @@ ensureCapacityInternal(count + len); shift(dstOffset, len); count += len; - if (s instanceof String) { - putStringAt(dstOffset, (String) s, start, end); + if (s instanceof String str && str.length() == len) { + putStringAt(dstOffset, str); } else { putCharsAt(dstOffset, s, start, end); } @@ -1741,11 +1741,6 @@ } } - private void putStringAt(int index, String str, int off, int end) { - inflateIfNeededFor(str); - str.getBytes(value, off, index, coder, end - off); - } - private void putStringAt(int index, String str) { inflateIfNeededFor(str); str.getBytes(value, index, coder); diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/lang/Class.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/Class.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/lang/Class.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/Class.java 2025-10-13 07:49:24.000000000 +0000 @@ -55,7 +55,9 @@ import java.lang.constant.Constable; import java.net.URL; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -3142,10 +3144,6 @@ return true; } - - /** protection domain returned when the internal domain is null */ - private static java.security.ProtectionDomain allPermDomain; - /** * Returns the {@code ProtectionDomain} of this class. If there is a * security manager installed, this method first calls the security @@ -3166,7 +3164,7 @@ * @see java.lang.RuntimePermission * @since 1.2 */ - public java.security.ProtectionDomain getProtectionDomain() { + public ProtectionDomain getProtectionDomain() { @SuppressWarnings("removal") SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -3175,26 +3173,30 @@ return protectionDomain(); } + /** Holder for the protection domain returned when the internal domain is null */ + private static class Holder { + private static final ProtectionDomain allPermDomain; + static { + Permissions perms = new Permissions(); + perms.add(SecurityConstants.ALL_PERMISSION); + allPermDomain = new ProtectionDomain(null, perms); + } + } + // package-private - java.security.ProtectionDomain protectionDomain() { - java.security.ProtectionDomain pd = getProtectionDomain0(); + ProtectionDomain protectionDomain() { + ProtectionDomain pd = getProtectionDomain0(); if (pd == null) { - if (allPermDomain == null) { - java.security.Permissions perms = - new java.security.Permissions(); - perms.add(SecurityConstants.ALL_PERMISSION); - allPermDomain = - new java.security.ProtectionDomain(null, perms); - } - pd = allPermDomain; + return Holder.allPermDomain; + } else { + return pd; } - return pd; } /** * Returns the ProtectionDomain of this class. */ - private native java.security.ProtectionDomain getProtectionDomain0(); + private native ProtectionDomain getProtectionDomain0(); /* * Return the Virtual Machine's Class object for the named diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/lang/invoke/CallSite.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/invoke/CallSite.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/lang/invoke/CallSite.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/invoke/CallSite.java 2025-10-13 07:49:24.000000000 +0000 @@ -139,12 +139,6 @@ } /** - * {@code CallSite} dependency context. - * JVM uses CallSite.context to store nmethod dependencies on the call site target. - */ - private final MethodHandleNatives.CallSiteContext context = MethodHandleNatives.CallSiteContext.make(this); - - /** * Returns the type of this call site's target. * Although targets may change, any call site's type is permanent, and can never change to an unequal type. * The {@code setTarget} method enforces this invariant by refusing any new target that does diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java 2025-10-13 07:49:24.000000000 +0000 @@ -71,31 +71,6 @@ boolean resolve, Object ifNotAvailable); - /** Represents a context to track nmethod dependencies on CallSite instance target. */ - static class CallSiteContext implements Runnable { - //@Injected JVM_nmethodBucket* vmdependencies; - //@Injected jlong last_cleanup; - - static CallSiteContext make(CallSite cs) { - final CallSiteContext newContext = new CallSiteContext(); - // CallSite instance is tracked by a Cleanable which clears native - // structures allocated for CallSite context. Though the CallSite can - // become unreachable, its Context is retained by the Cleanable instance - // (which is referenced from Cleaner instance which is referenced from - // CleanerFactory class) until cleanup is performed. - CleanerFactory.cleaner().register(cs, newContext); - return newContext; - } - - @Override - public void run() { - MethodHandleNatives.clearCallSiteContext(this); - } - } - - /** Invalidate all recorded nmethods. */ - private static native void clearCallSiteContext(CallSiteContext context); - private static native void registerNatives(); static { registerNatives(); diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/math/BigInteger.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/math/BigInteger.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/math/BigInteger.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/math/BigInteger.java 2025-10-13 07:49:24.000000000 +0000 @@ -315,12 +315,18 @@ throw new NumberFormatException("Zero length BigInteger"); } Objects.checkFromIndexSize(off, len, val.length); + if (len == 0) { + mag = ZERO.mag; + signum = ZERO.signum; + return; + } - if (val[off] < 0) { - mag = makePositive(val, off, len); + int b = val[off]; + if (b < 0) { + mag = makePositive(b, val, off, len); signum = -1; } else { - mag = stripLeadingZeroBytes(val, off, len); + mag = stripLeadingZeroBytes(b, val, off, len); signum = (mag.length == 0 ? 0 : 1); } if (mag.length >= MAX_MAG_LENGTH) { @@ -4568,77 +4574,167 @@ return keep == 0 ? val : java.util.Arrays.copyOfRange(val, keep, vlen); } - /** + private static int[] stripLeadingZeroBytes(byte[] a, int from, int len) { + return stripLeadingZeroBytes(Integer.MIN_VALUE, a, from, len); + } + + /* * Returns a copy of the input array stripped of any leading zero bytes. + * The returned array is either empty, or its 0-th element is non-zero, + * meeting the "minimal" requirement for field mag (see comment on mag). + * + * The range [from, from + len) must be well-formed w.r.t. array a. + * + * b < -128 means that a[from] has not yet been read. + * Otherwise, b must be a[from], have been read only once before invoking + * this method, and len > 0 must hold. */ - private static int[] stripLeadingZeroBytes(byte[] a, int off, int len) { - int indexBound = off + len; - int keep; - - // Find first nonzero byte - for (keep = off; keep < indexBound && a[keep] == 0; keep++) - ; - - // Allocate new array and copy relevant part of input array - int intLength = ((indexBound - keep) + 3) >>> 2; - int[] result = new int[intLength]; - int b = indexBound - 1; - for (int i = intLength-1; i >= 0; i--) { - result[i] = a[b--] & 0xff; - int bytesRemaining = b - keep + 1; - int bytesToTransfer = Math.min(3, bytesRemaining); - for (int j=8; j <= (bytesToTransfer << 3); j += 8) - result[i] |= ((a[b--] & 0xff) << j); + private static int[] stripLeadingZeroBytes(int b, byte[] a, int from, int len) { + /* + * Except for the first byte, each read access to the input array a + * is of the form a[from++]. + * The index from is never otherwise altered, except right below, + * and only increases in steps of 1, always up to index to. + * Hence, each byte in the array is read exactly once, from lower to + * higher indices (from most to least significant byte). + */ + if (len == 0) { + return ZERO.mag; } - return result; + int to = from + len; + if (b < -128) { + b = a[from]; + } + /* Either way, a[from] has now been read exactly once, skip to next. */ + ++from; + /* + * Set up the shortest int[] for the sequence of the bytes + * b, a[from+1], ..., a[to-1] (len > 0) + * Shortest means first skipping leading zeros. + */ + for (; b == 0 && from < to; b = a[from++]) + ; //empty body + if (b == 0) { + /* Here, from == to as well. All bytes are zeros. */ + return ZERO.mag; + } + /* + * Allocate just enough ints to hold (to - from + 1) bytes, that is + * ((to - from + 1) + 3) / 4 = (to - from) / 4 + 1 + */ + int[] res = new int[((to - from) >> 2) + 1]; + /* + * A "digit" is a group of 4 adjacent bytes aligned w.r.t. index to. + * (Implied 0 bytes are prepended as needed.) + * b is the most significant byte not 0. + * Digit d0 spans the range of indices that includes current (from - 1). + */ + int d0 = b & 0xFF; + while (((to - from) & 0x3) != 0) { + d0 = d0 << 8 | a[from++] & 0xFF; + } + res[0] = d0; + /* + * Prepare the remaining digits. + * (to - from) is a multiple of 4, so prepare an int for every 4 bytes. + * This is a candidate for Unsafe.copy[Swap]Memory(). + */ + int i = 1; + while (from < to) { + res[i++] = a[from++] << 24 | (a[from++] & 0xFF) << 16 + | (a[from++] & 0xFF) << 8 | (a[from++] & 0xFF); + } + return res; } - /** + /* * Takes an array a representing a negative 2's-complement number and * returns the minimal (no leading zero bytes) unsigned whose value is -a. + * + * len > 0 must hold. + * The range [from, from + len) must be well-formed w.r.t. array a. + * b is assumed to be the result of reading a[from] and to meet b < 0. */ - private static int[] makePositive(byte[] a, int off, int len) { - int keep, k; - int indexBound = off + len; - - // Find first non-sign (0xff) byte of input - for (keep=off; keep < indexBound && a[keep] == -1; keep++) - ; - - - /* Allocate output array. If all non-sign bytes are 0x00, we must - * allocate space for one extra output byte. */ - for (k=keep; k < indexBound && a[k] == 0; k++) - ; - - int extraByte = (k == indexBound) ? 1 : 0; - int intLength = ((indexBound - keep + extraByte) + 3) >>> 2; - int result[] = new int[intLength]; - - /* Copy one's complement of input into output, leaving extra - * byte (if it exists) == 0x00 */ - int b = indexBound - 1; - for (int i = intLength-1; i >= 0; i--) { - result[i] = a[b--] & 0xff; - int numBytesToTransfer = Math.min(3, b-keep+1); - if (numBytesToTransfer < 0) - numBytesToTransfer = 0; - for (int j=8; j <= 8*numBytesToTransfer; j += 8) - result[i] |= ((a[b--] & 0xff) << j); - - // Mask indicates which bits must be complemented - int mask = -1 >>> (8*(3-numBytesToTransfer)); - result[i] = ~result[i] & mask; - } - - // Add one to one's complement to generate two's complement - for (int i=result.length-1; i >= 0; i--) { - result[i] = (int)((result[i] & LONG_MASK) + 1); - if (result[i] != 0) - break; + private static int[] makePositive(int b, byte[] a, int from, int len) { + /* + * By assumption, b == a[from] < 0 and len > 0. + * + * First collect the bytes into the resulting array res. + * Then convert res to two's complement. + * + * Except for b == a[from], each read access to the input array a + * is of the form a[from++]. + * The index from is never otherwise altered, except right below, + * and only increases in steps of 1, always up to index to. + * Hence, each byte in the array is read exactly once, from lower to + * higher indices (from most to least significant byte). + */ + int to = from + len; + /* b == a[from] has been read exactly once, skip to next index. */ + ++from; + /* Skip leading -1 bytes. */ + for (; b == -1 && from < to; b = a[from++]) + ; //empty body + /* + * A "digit" is a group of 4 adjacent bytes aligned w.r.t. index to. + * b is the most significant byte not -1, or -1 only if from == to. + * Digit d0 spans the range of indices that includes current (from - 1). + * (Implied -1 bytes are prepended to array a as needed.) + * It usually corresponds to res[0], except for the special case below. + */ + int d0 = -1 << 8 | b & 0xFF; + while (((to - from) & 0x3) != 0) { + d0 = d0 << 8 | (b = a[from++]) & 0xFF; + } + int f = from; // keeps the current from for sizing purposes later + /* Skip zeros adjacent to d0, if at all. */ + for (; b == 0 && from < to; b = a[from++]) + ; //empty body + /* + * b is the most significant non-zero byte at or after (f - 1), + * or 0 only if from == to. + * Digit d spans the range of indices that includes (f - 1). + */ + int d = b & 0xFF; + while (((to - from) & 0x3) != 0) { + d = d << 8 | a[from++] & 0xFF; } - - return result; + /* + * If the situation here is like this: + * index: f to == from + * ..., -1,-1, 0,0,0,0, 0,0,0,0, ..., 0,0,0,0 + * digit: d0 d + * then, as shown, the number of zeros is a positive multiple of 4. + * The array res needs a minimal length of (1 + 1 + (to - f) / 4) + * to accommodate the two's complement, including a leading 1. + * In any other case, there is at least one byte that is non-zero. + * The array for the two's complement has length (0 + 1 + (to - f) / 4). + * c is 1, resp., 0 for the two situations. + */ + int c = (to - from | d0 | d) == 0 ? 1 : 0; + int[] res = new int[c + 1 + ((to - f) >> 2)]; + res[0] = c == 0 ? d0 : -1; + int i = res.length - ((to - from) >> 2); + if (i > 1) { + res[i - 1] = d; + } + /* + * Prepare the remaining digits. + * (to - from) is a multiple of 4, so prepare an int for every 4 bytes. + * This is a candidate for Unsafe.copy[Swap]Memory(). + */ + while (from < to) { + res[i++] = a[from++] << 24 | (a[from++] & 0xFF) << 16 + | (a[from++] & 0xFF) << 8 | (a[from++] & 0xFF); + } + /* Convert to two's complement. Here, i == res.length */ + while (--i >= 0 && res[i] == 0) + ; // empty body + res[i] = -res[i]; + while (--i >= 0) { + res[i] = ~res[i]; + } + return res; } /** diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/text/MessageFormat.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/text/MessageFormat.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/text/MessageFormat.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/text/MessageFormat.java 2025-10-13 07:49:24.000000000 +0000 @@ -1662,7 +1662,7 @@ // Check the correctness of arguments and offsets if (isValid) { - int lastOffset = patt.length() + 1; + int lastOffset = patt.length(); for (int i = maxOff; i >= 0; --i) { if (argNums[i] < 0 || argNums[i] >= MAX_ARGUMENT_INDEX || offs[i] < 0 || offs[i] > lastOffset) { diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/Currency.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/Currency.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/Currency.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/Currency.java 2025-10-13 07:49:24.000000000 +0000 @@ -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 */ @@ -319,7 +319,8 @@ // or in the list of other currencies. boolean found = false; if (currencyCode.length() != 3) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + "The input currency code: \"%s\" must have a length of 3 characters".formatted(currencyCode)); } char char1 = currencyCode.charAt(0); char char2 = currencyCode.charAt(1); @@ -342,7 +343,8 @@ if (!found) { OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode); if (ocEntry == null) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + "The input currency code: \"%s\" is not a valid ISO 4217 code".formatted(currencyCode)); } defaultFractionDigits = ocEntry.fraction; numericCode = ocEntry.numericCode; @@ -397,7 +399,8 @@ String country = CalendarDataUtility.findRegionOverride(locale).getCountry(); if (country == null || !country.matches("^[a-zA-Z]{2}$")) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + "The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale)); } char char1 = country.charAt(0); @@ -414,7 +417,8 @@ } else { // special cases if (tableEntry == INVALID_COUNTRY_ENTRY) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + "The country of the input locale: \"%s\" is not a valid ISO 3166 country code".formatted(locale)); } if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) { return null; @@ -679,7 +683,8 @@ */ private static int getMainTableEntry(char char1, char char2) { if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + "The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2)); } return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')]; } @@ -690,7 +695,8 @@ */ private static void setMainTableEntry(char char1, char char2, int entry) { if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + "The country code: \"%c%c\" is not a valid ISO 3166 code".formatted(char1, char2)); } mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry; } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/Formatter.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/Formatter.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/Formatter.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/Formatter.java 2025-10-13 07:49:24.000000000 +0000 @@ -4765,9 +4765,9 @@ DECIMAL_FLOAT, HEXADECIMAL_FLOAT, HEXADECIMAL_FLOAT_UPPER, - LINE_SEPARATOR, - PERCENT_SIGN -> true; - default -> false; + LINE_SEPARATOR -> true; + // Don't put PERCENT_SIGN inside switch, as that will make the method size exceed 325 and cannot be inlined. + default -> c == PERCENT_SIGN; }; } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java 2025-10-13 07:49:24.000000000 +0000 @@ -1059,7 +1059,7 @@ final Subscriber subscriber; final BiConsumer, ? super Throwable> onNextHandler; Executor executor; // null on error - Thread waiter; // blocked producer thread + volatile Thread waiter; // blocked producer thread Throwable pendingError; // holds until onError issued BufferedSubscription next; // used only by publisher BufferedSubscription nextRetry; // used only by publisher diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java 2025-10-13 07:49:24.000000000 +0000 @@ -278,6 +278,40 @@ } /** + * Repeatedly invokes acquire, if its execution throws an Error or a Runtime Exception, + * using an Unsafe.park-based backoff + * @param node which to reacquire + * @param arg the acquire argument + */ + private final void reacquire(Node node, long arg) { + try { + acquire(node, arg, false, false, false, 0L); + } catch (Error | RuntimeException firstEx) { + // While we currently do not emit an JFR events in this situation, mainly + // because the conditions under which this happens are such that it + // cannot be presumed to be possible to actually allocate an event, and + // using a preconstructed one would have limited value in serviceability. + // Having said that, the following place would be the more appropriate + // place to put such logic: + // emit JFR event + + for (long nanos = 1L;;) { + U.park(false, nanos); // must use Unsafe park to sleep + if (nanos < 1L << 30) // max about 1 second + nanos <<= 1; + + try { + acquire(node, arg, false, false, false, 0L); + } catch (Error | RuntimeException ignored) { + continue; + } + + throw firstEx; + } + } + } + + /** * Main acquire method, invoked by all exported acquire methods. * * @param node null unless a reacquiring Condition @@ -1294,7 +1328,7 @@ } LockSupport.setCurrentBlocker(null); node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (interrupted) Thread.currentThread().interrupt(); } @@ -1341,7 +1375,7 @@ } LockSupport.setCurrentBlocker(null); node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (interrupted) { if (cancelled) { unlinkCancelledWaiters(node); @@ -1384,7 +1418,7 @@ LockSupport.parkNanos(this, nanos); } node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (cancelled) { unlinkCancelledWaiters(node); if (interrupted) @@ -1428,7 +1462,7 @@ LockSupport.parkUntil(this, abstime); } node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (cancelled) { unlinkCancelledWaiters(node); if (interrupted) @@ -1473,7 +1507,7 @@ LockSupport.parkNanos(this, nanos); } node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (cancelled) { unlinkCancelledWaiters(node); if (interrupted) diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java 2025-10-13 07:49:24.000000000 +0000 @@ -657,6 +657,40 @@ } /** + * Repeatedly invokes acquire, if its execution throws an Error or a Runtime Exception, + * using an Unsafe.park-based backoff + * @param node which to reacquire + * @param arg the acquire argument + */ + private final void reacquire(Node node, int arg) { + try { + acquire(node, arg, false, false, false, 0L); + } catch (Error | RuntimeException firstEx) { + // While we currently do not emit an JFR events in this situation, mainly + // because the conditions under which this happens are such that it + // cannot be presumed to be possible to actually allocate an event, and + // using a preconstructed one would have limited value in serviceability. + // Having said that, the following place would be the more appropriate + // place to put such logic: + // emit JFR event + + for (long nanos = 1L;;) { + U.park(false, nanos); // must use Unsafe park to sleep + if (nanos < 1L << 30) // max about 1 second + nanos <<= 1; + + try { + acquire(node, arg, false, false, false, 0L); + } catch (Error | RuntimeException ignored) { + continue; + } + + throw firstEx; + } + } + } + + /** * Main acquire method, invoked by all exported acquire methods. * * @param node null unless a reacquiring Condition @@ -1673,7 +1707,7 @@ } LockSupport.setCurrentBlocker(null); node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (interrupted) Thread.currentThread().interrupt(); } @@ -1720,7 +1754,7 @@ } LockSupport.setCurrentBlocker(null); node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (interrupted) { if (cancelled) { unlinkCancelledWaiters(node); @@ -1763,7 +1797,7 @@ LockSupport.parkNanos(this, nanos); } node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (cancelled) { unlinkCancelledWaiters(node); if (interrupted) @@ -1807,7 +1841,7 @@ LockSupport.parkUntil(this, abstime); } node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (cancelled) { unlinkCancelledWaiters(node); if (interrupted) @@ -1852,7 +1886,7 @@ LockSupport.parkNanos(this, nanos); } node.clearStatus(); - acquire(node, savedState, false, false, false, 0L); + reacquire(node, savedState); if (cancelled) { unlinkCancelledWaiters(node); if (interrupted) diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/zip/GZIPInputStream.java openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/zip/GZIPInputStream.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/java/util/zip/GZIPInputStream.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/java/util/zip/GZIPInputStream.java 2025-10-13 07:49:24.000000000 +0000 @@ -256,23 +256,17 @@ (readUInt(in) != (inf.getBytesWritten() & 0xffffffffL))) throw new ZipException("Corrupt GZIP trailer"); - // If there are more bytes available in "in" or - // the leftover in the "inf" is > 26 bytes: - // this.trailer(8) + next.header.min(10) + next.trailer(8) // try concatenated case - if (this.in.available() > 0 || n > 26) { - int m = 8; // this.trailer - try { - m += readHeader(in); // next.header - } catch (IOException ze) { - return true; // ignore any malformed, do nothing - } - inf.reset(); - if (n > m) - inf.setInput(buf, len - n + m, n - m); - return false; + int m = 8; // this.trailer + try { + m += readHeader(in); // next.header + } catch (IOException ze) { + return true; // ignore any malformed, do nothing } - return true; + inf.reset(); + if (n > m) + inf.setInput(buf, len - n + m, n - m); + return false; } /* diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/jdk/internal/platform/Metrics.java openjdk-21-21.0.9+10/src/java.base/share/classes/jdk/internal/platform/Metrics.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/jdk/internal/platform/Metrics.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/jdk/internal/platform/Metrics.java 2025-10-13 07:49:24.000000000 +0000 @@ -71,6 +71,23 @@ */ public String getProvider(); + /** + * Determines whether or not the underlying system + * has useful metrics (a.k.a. is containerized). + * + * @implNote + * Note that Metrics on some systems aren't useful. + * For example on a regular Linux system with cgroups + * present, with no limits enforced and not running in + * a container, Metric aren't useful. This can be used + * in order to determine if the system is containerized. + * + * @return true when the JVM runs in containerized mode. + * false otherwise. + * + */ + public boolean isContainerized(); + /***************************************************************** * CPU Accounting Subsystem diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/launcher/LauncherHelper.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/launcher/LauncherHelper.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/launcher/LauncherHelper.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/launcher/LauncherHelper.java 2025-10-13 07:49:24.000000000 +0000 @@ -71,6 +71,7 @@ import java.util.Properties; import java.util.ResourceBundle; import java.util.Set; +import java.util.TimeZone; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarFile; @@ -295,6 +296,8 @@ Locale.getDefault(Category.DISPLAY).getDisplayName()); ostream.println(INDENT + "default format locale = " + Locale.getDefault(Category.FORMAT).getDisplayName()); + ostream.println(INDENT + "default timezone = " + + TimeZone.getDefault().getID()); ostream.println(INDENT + "tzdata version = " + ZoneInfoFile.getVersion()); if (!summaryMode) { @@ -347,6 +350,10 @@ final long longRetvalNotSupported = -2; ostream.println(INDENT + "Provider: " + c.getProvider()); + if (!c.isContainerized()) { + ostream.println(INDENT + "System not containerized."); + return; + } ostream.println(INDENT + "Effective CPU Count: " + c.getEffectiveCpuCount()); ostream.println(formatCpuVal(c.getCpuPeriod(), INDENT + "CPU Period: ", longRetvalNotSupported)); ostream.println(formatCpuVal(c.getCpuQuota(), INDENT + "CPU Quota: ", longRetvalNotSupported)); diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java 2025-10-13 07:49:24.000000000 +0000 @@ -418,6 +418,10 @@ calls getInputStream after disconnect */ private Exception rememberedException = null; + /* Remembered Exception, we will throw it again if somebody + calls getOutputStream after disconnect or error */ + private Exception rememberedExceptionOut = null; + /* If we decide we want to reuse a client, we put it here */ private HttpClient reuseClient = null; @@ -1445,6 +1449,14 @@ + " if doOutput=false - call setDoOutput(true)"); } + if (rememberedExceptionOut != null) { + if (rememberedExceptionOut instanceof RuntimeException) { + throw new RuntimeException(rememberedExceptionOut); + } else { + throw getChainedException((IOException) rememberedExceptionOut); + } + } + if (method.equals("GET")) { method = "POST"; // Backward compatibility } @@ -1504,9 +1516,11 @@ int i = responseCode; disconnectInternal(); responseCode = i; + rememberedExceptionOut = e; throw e; } catch (RuntimeException | IOException e) { disconnectInternal(); + rememberedExceptionOut = e; throw e; } } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/nio/cs/Unicode.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/nio/cs/Unicode.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/nio/cs/Unicode.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/nio/cs/Unicode.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, 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 @@ -45,6 +45,12 @@ || (cs instanceof UTF_16BE) || (cs instanceof UTF_16LE) || (cs instanceof UTF_16LE_BOM) + || (cs instanceof CESU_8) + || (cs instanceof UTF_32) + || (cs instanceof UTF_32BE) + || (cs instanceof UTF_32BE_BOM) + || (cs instanceof UTF_32LE) + || (cs instanceof UTF_32LE_BOM) || (cs.name().equals("GBK")) || (cs.name().equals("GB18030")) || (cs.name().equals("ISO-8859-2")) diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/Alert.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/Alert.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/Alert.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/Alert.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -123,13 +123,13 @@ } if (cause instanceof IOException) { - return new SSLException(reason, cause); + return new SSLException("(" + description + ") " + reason, cause); } else if ((this == UNEXPECTED_MESSAGE)) { - return new SSLProtocolException(reason, cause); + return new SSLProtocolException("(" + description + ") " + reason, cause); } else if (handshakeOnly) { - return new SSLHandshakeException(reason, cause); + return new SSLHandshakeException("(" + description + ") " + reason, cause); } else { - return new SSLException(reason, cause); + return new SSLException("(" + description + ") " + reason, cause); } } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -25,6 +25,8 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; @@ -97,26 +99,21 @@ } // Produce the extension. - if (chc.localSupportedSignAlgs == null) { - chc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols); - } + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); int vectorLen = SignatureScheme.sizeInRecord() * - chc.localSupportedSignAlgs.size(); + chc.localSupportedCertSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; ByteBuffer m = ByteBuffer.wrap(extData); Record.putInt16(m, vectorLen); - for (SignatureScheme ss : chc.localSupportedSignAlgs) { + for (SignatureScheme ss : chc.localSupportedCertSignAlgs) { Record.putInt16(m, ss.id); } // Update the context. chc.handshakeExtensions.put( SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT, - new SignatureSchemesSpec(chc.localSupportedSignAlgs)); + new SignatureSchemesSpec(chc.localSupportedCertSignAlgs)); return extData; } @@ -191,7 +188,9 @@ SignatureScheme.getSupportedAlgorithms( shc.sslConfig, shc.algorithmConstraints, shc.negotiatedProtocol, - spec.signatureSchemes); + spec.signatureSchemes, + CERTIFICATE_SCOPE); + shc.peerRequestedCertSignSchemes = schemes; shc.handshakeSession.setPeerSupportedSignatureAlgorithms(schemes); @@ -240,24 +239,21 @@ } // Produce the extension. - List sigAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, - List.of(shc.negotiatedProtocol)); - - int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); + // localSupportedCertSignAlgs has been already updated when we set + // the negotiated protocol. + int vectorLen = SignatureScheme.sizeInRecord() + * shc.localSupportedCertSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; ByteBuffer m = ByteBuffer.wrap(extData); Record.putInt16(m, vectorLen); - for (SignatureScheme ss : sigAlgs) { + for (SignatureScheme ss : shc.localSupportedCertSignAlgs) { Record.putInt16(m, ss.id); } // Update the context. shc.handshakeExtensions.put( SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT, - new SignatureSchemesSpec(shc.localSupportedSignAlgs)); + new SignatureSchemesSpec(shc.localSupportedCertSignAlgs)); return extData; } @@ -331,7 +327,9 @@ SignatureScheme.getSupportedAlgorithms( chc.sslConfig, chc.algorithmConstraints, chc.negotiatedProtocol, - spec.signatureSchemes); + spec.signatureSchemes, + CERTIFICATE_SCOPE); + chc.peerRequestedCertSignSchemes = schemes; chc.handshakeSession.setPeerSupportedSignatureAlgorithms(schemes); } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java 2025-10-13 07:49:24.000000000 +0000 @@ -381,7 +381,7 @@ if (shc.sslConfig.clientAuthType != ClientAuthType.CLIENT_AUTH_REQUESTED) { // unexpected or require client authentication - throw shc.conContext.fatal(Alert.BAD_CERTIFICATE, + throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "Empty client certificate chain"); } else { return; @@ -693,46 +693,6 @@ } } - /** - * When a failure happens during certificate checking from an - * {@link X509TrustManager}, determine what TLS alert description - * to use. - * - * @param cexc The exception thrown by the {@link X509TrustManager} - * - * @return A byte value corresponding to a TLS alert description number. - */ - private static Alert getCertificateAlert( - ClientHandshakeContext chc, CertificateException cexc) { - // The specific reason for the failure will determine how to - // set the alert description value - Alert alert = Alert.CERTIFICATE_UNKNOWN; - - Throwable baseCause = cexc.getCause(); - if (baseCause instanceof CertPathValidatorException cpve) { - Reason reason = cpve.getReason(); - if (reason == BasicReason.REVOKED) { - alert = chc.staplingActive ? - Alert.BAD_CERT_STATUS_RESPONSE : - Alert.CERTIFICATE_REVOKED; - } else if ( - reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) { - alert = chc.staplingActive ? - Alert.BAD_CERT_STATUS_RESPONSE : - Alert.CERTIFICATE_UNKNOWN; - } else if (reason == BasicReason.ALGORITHM_CONSTRAINED) { - alert = Alert.UNSUPPORTED_CERTIFICATE; - } else if (reason == BasicReason.EXPIRED) { - alert = Alert.CERTIFICATE_EXPIRED; - } else if (reason == BasicReason.INVALID_SIGNATURE || - reason == BasicReason.NOT_YET_VALID) { - alert = Alert.BAD_CERTIFICATE; - } - } - - return alert; - } - } /** @@ -1163,7 +1123,7 @@ shc.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_VERIFY.id); if (shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED) { - throw shc.conContext.fatal(Alert.BAD_CERTIFICATE, + throw shc.conContext.fatal(Alert.CERTIFICATE_REQUIRED, "Empty client certificate chain"); } else { // optional client authentication @@ -1187,7 +1147,7 @@ T13CertificateMessage certificateMessage )throws IOException { if (certificateMessage.certEntries == null || certificateMessage.certEntries.isEmpty()) { - throw chc.conContext.fatal(Alert.BAD_CERTIFICATE, + throw chc.conContext.fatal(Alert.DECODE_ERROR, "Empty server certificate chain"); } @@ -1330,37 +1290,57 @@ return certs; } - /** - * When a failure happens during certificate checking from an - * {@link X509TrustManager}, determine what TLS alert description - * to use. - * - * @param cexc The exception thrown by the {@link X509TrustManager} - * - * @return A byte value corresponding to a TLS alert description number. - */ - private static Alert getCertificateAlert( - ClientHandshakeContext chc, CertificateException cexc) { - // The specific reason for the failure will determine how to - // set the alert description value - Alert alert = Alert.CERTIFICATE_UNKNOWN; - - Throwable baseCause = cexc.getCause(); - if (baseCause instanceof CertPathValidatorException cpve) { - Reason reason = cpve.getReason(); - if (reason == BasicReason.REVOKED) { - alert = chc.staplingActive ? - Alert.BAD_CERT_STATUS_RESPONSE : - Alert.CERTIFICATE_REVOKED; - } else if ( - reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) { - alert = chc.staplingActive ? - Alert.BAD_CERT_STATUS_RESPONSE : - Alert.CERTIFICATE_UNKNOWN; + } + + /** + * When a failure happens during certificate checking from an + * {@link X509TrustManager}, determine what TLS alert description + * to use. + * + * @param cexc The exception thrown by the {@link X509TrustManager} + * @return A byte value corresponding to a TLS alert description number. + */ + private static Alert getCertificateAlert( + ClientHandshakeContext chc, CertificateException cexc) { + // The specific reason for the failure will determine how to + // set the alert description value + Alert alert = Alert.CERTIFICATE_UNKNOWN; + + Throwable baseCause = cexc.getCause(); + if (baseCause instanceof CertPathValidatorException cpve) { + Reason reason = cpve.getReason(); + if (reason == BasicReason.REVOKED) { + alert = chc.staplingActive ? + Alert.BAD_CERT_STATUS_RESPONSE : + Alert.CERTIFICATE_REVOKED; + } else if (reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) { + alert = chc.staplingActive ? + Alert.BAD_CERT_STATUS_RESPONSE : + Alert.CERTIFICATE_UNKNOWN; + } else if (reason == BasicReason.EXPIRED) { + alert = Alert.CERTIFICATE_EXPIRED; + } else if (reason == BasicReason.INVALID_SIGNATURE + || reason == BasicReason.NOT_YET_VALID) { + alert = Alert.BAD_CERTIFICATE; + } else if (reason == BasicReason.ALGORITHM_CONSTRAINED) { + alert = Alert.UNSUPPORTED_CERTIFICATE; + + // Per TLSv1.3 RFC we MUST abort the handshake with a + // "bad_certificate" alert if we reject certificate + // because of the signature using MD5 or SHA1 algorithm. + if (chc.negotiatedProtocol != null + && chc.negotiatedProtocol.useTLS13PlusSpec()) { + final String exMsg = cexc.getMessage().toUpperCase(); + + if (exMsg.contains("MD5WITH") + || exMsg.contains("SHA1WITH")) { + alert = Alert.BAD_CERTIFICATE; + } } } - - return alert; } + + return alert; } + } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -25,6 +25,9 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; +import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.security.PrivateKey; @@ -396,7 +399,6 @@ iae); } - if (clientAlias == null) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No available client authentication"); @@ -632,15 +634,18 @@ public byte[] produce(ConnectionContext context, HandshakeMessage message) throws IOException { // The producing happens in server side only. - ServerHandshakeContext shc = (ServerHandshakeContext)context; - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); - } + ServerHandshakeContext shc = (ServerHandshakeContext) context; + + // According to TLSv1.2 RFC, CertificateRequest message must + // contain signature schemes supported for both: + // handshake signatures and certificate signatures. + // localSupportedSignAlgs and localSupportedCertSignAlgs have been + // already updated when we set the negotiated protocol. + List certReqSignAlgs = + new ArrayList<>(shc.localSupportedSignAlgs); + certReqSignAlgs.retainAll(shc.localSupportedCertSignAlgs); - if (shc.localSupportedSignAlgs.isEmpty()) { + if (certReqSignAlgs.isEmpty()) { throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "No supported signature algorithm"); } @@ -649,7 +654,7 @@ shc.sslContext.getX509TrustManager().getAcceptedIssuers(); T12CertificateRequestMessage crm = new T12CertificateRequestMessage( shc, caCerts, shc.negotiatedCipherSuite.keyExchange, - shc.localSupportedSignAlgs); + certReqSignAlgs); if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced CertificateRequest handshake message", crm); @@ -730,19 +735,29 @@ chc.handshakeProducers.put(SSLHandshake.CERTIFICATE.id, SSLHandshake.CERTIFICATE); - List sss = + List signAlgs = SignatureScheme.getSupportedAlgorithms( chc.sslConfig, chc.algorithmConstraints, chc.negotiatedProtocol, - crm.algorithmIds); - if (sss.isEmpty()) { + crm.algorithmIds, + HANDSHAKE_SCOPE); + + List signCertAlgs = + SignatureScheme.getSupportedAlgorithms( + chc.sslConfig, + chc.algorithmConstraints, chc.negotiatedProtocol, + crm.algorithmIds, + CERTIFICATE_SCOPE); + + if (signAlgs.isEmpty() || signCertAlgs.isEmpty()) { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "No supported signature algorithm"); } - chc.peerRequestedSignatureSchemes = sss; - chc.peerRequestedCertSignSchemes = sss; // use the same schemes - chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); + chc.peerRequestedSignatureSchemes = signAlgs; + chc.peerRequestedCertSignSchemes = signCertAlgs; + chc.handshakeSession.setPeerSupportedSignatureAlgorithms(signCertAlgs); + try { chc.peerSupportedAuthorities = crm.getAuthorities(); } catch (IllegalArgumentException iae) { diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/ClientHello.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/ClientHello.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/ClientHello.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/ClientHello.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -825,6 +825,10 @@ "Negotiated protocol version: " + negotiatedProtocol.name); } + // Protocol version is negotiated, update locally supported + // signature schemes according to the protocol being used. + SignatureScheme.updateHandshakeLocalSupportedAlgs(context); + // Consume the handshake message for the specific protocol version. if (negotiatedProtocol.isDTLS) { if (negotiatedProtocol.useTLS13PlusSpec()) { diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -72,7 +72,7 @@ // consolidated parameters final List activeProtocols; final List activeCipherSuites; - final AlgorithmConstraints algorithmConstraints; + final SSLAlgorithmConstraints algorithmConstraints; final ProtocolVersion maximumActiveProtocol; // output stream @@ -127,6 +127,7 @@ // SignatureScheme List localSupportedSignAlgs; + List localSupportedCertSignAlgs; List peerRequestedSignatureSchemes; List peerRequestedCertSignSchemes; diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/PostHandshakeContext.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -43,7 +43,7 @@ "Post-handshake not supported in " + negotiatedProtocol.name); } - this.localSupportedSignAlgs = new ArrayList<>( + this.localSupportedCertSignAlgs = new ArrayList<>( context.conSession.getLocalSupportedSignatureSchemes()); // Add the potential post-handshake consumers. diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -440,16 +440,11 @@ result = false; } - // Make sure that the server handshake context's localSupportedSignAlgs - // field is populated. This is particularly important when - // client authentication was used in an initial session, and it is - // now being resumed. - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); - } + // Make sure that the server handshake context's + // localSupportedCertSignAlgs field is populated. This is particularly + // important when client authentication was used in an initial session, + // and it is now being resumed. + SignatureScheme.updateHandshakeLocalSupportedAlgs(shc); // Validate the required client authentication. if (result && @@ -470,7 +465,7 @@ Collection sessionSigAlgs = s.getLocalSupportedSignatureSchemes(); if (result && - !shc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) { + !shc.localSupportedCertSignAlgs.containsAll(sessionSigAlgs)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Can't resume. Session uses different " + @@ -664,7 +659,7 @@ // Make sure the list of supported signature algorithms matches Collection sessionSigAlgs = chc.resumingSession.getLocalSupportedSignatureSchemes(); - if (!chc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) { + if (!chc.localSupportedCertSignAlgs.containsAll(sessionSigAlgs)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Existing session uses different " + "signature algorithms"); diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, 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 @@ -42,11 +42,11 @@ */ final class SSLAlgorithmConstraints implements AlgorithmConstraints { - private static final AlgorithmConstraints tlsDisabledAlgConstraints = + private static final DisabledAlgorithmConstraints tlsDisabledAlgConstraints = new DisabledAlgorithmConstraints(PROPERTY_TLS_DISABLED_ALGS, new SSLAlgorithmDecomposer()); - private static final AlgorithmConstraints x509DisabledAlgConstraints = + private static final DisabledAlgorithmConstraints x509DisabledAlgConstraints = new DisabledAlgorithmConstraints(PROPERTY_CERTPATH_DISABLED_ALGS, new SSLAlgorithmDecomposer(true)); @@ -56,11 +56,11 @@ private final boolean enabledX509DisabledAlgConstraints; // the default algorithm constraints - static final AlgorithmConstraints DEFAULT = + static final SSLAlgorithmConstraints DEFAULT = new SSLAlgorithmConstraints(null, true); // the default SSL only algorithm constraints - static final AlgorithmConstraints DEFAULT_SSL_ONLY = + static final SSLAlgorithmConstraints DEFAULT_SSL_ONLY = new SSLAlgorithmConstraints(null, false); private SSLAlgorithmConstraints(AlgorithmConstraints userSpecifiedConstraints, @@ -84,11 +84,11 @@ * @param userSpecifiedConstraints additional constraints to check * @return a SSLAlgorithmConstraints instance */ - static AlgorithmConstraints wrap(AlgorithmConstraints userSpecifiedConstraints) { + static SSLAlgorithmConstraints wrap(AlgorithmConstraints userSpecifiedConstraints) { return wrap(userSpecifiedConstraints, true); } - private static AlgorithmConstraints wrap( + private static SSLAlgorithmConstraints wrap( AlgorithmConstraints userSpecifiedConstraints, boolean withDefaultCertPathConstraints) { if (nullIfDefault(userSpecifiedConstraints) == null) { @@ -199,22 +199,22 @@ if (peerSpecifiedConstraints != null) { permitted = peerSpecifiedConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted && userSpecifiedConstraints != null) { permitted = userSpecifiedConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted) { permitted = tlsDisabledAlgConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted && enabledX509DisabledAlgConstraints) { permitted = x509DisabledAlgConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } return permitted; @@ -252,27 +252,31 @@ if (peerSpecifiedConstraints != null) { permitted = peerSpecifiedConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted && userSpecifiedConstraints != null) { permitted = userSpecifiedConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted) { permitted = tlsDisabledAlgConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted && enabledX509DisabledAlgConstraints) { permitted = x509DisabledAlgConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } return permitted; } + // Checks if algorithm is disabled for the given TLS scopes. + boolean permits(String algorithm, Set scopes) { + return tlsDisabledAlgConstraints.permits(algorithm, scopes); + } private static class SupportedSignatureAlgorithmConstraints implements AlgorithmConstraints { diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SSLLogger.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLLogger.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SSLLogger.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLLogger.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -143,8 +143,10 @@ if (property.contains("all")) { return true; } else { - int offset = property.indexOf("ssl"); - if (offset != -1 && property.indexOf("sslctx", offset) != -1) { + // remove first occurrence of "sslctx" since + // it interferes with search for "ssl" + String modified = property.replaceFirst("sslctx", ""); + if (modified.contains("ssl")) { // don't enable data and plaintext options by default if (!(option.equals("data") || option.equals("packet") diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SSLScope.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLScope.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SSLScope.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLScope.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, 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. 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 sun.security.ssl; + +/* + * Scopes defining different parts of TLS protocol. + */ + +public enum SSLScope { + // Handshake signature scope as in signature_algorithms extension. + HANDSHAKE_SIGNATURE("HandshakeSignature"), + + // Certificate signature scope as in signature_algorithms_cert extension. + CERTIFICATE_SIGNATURE("CertificateSignature"); + + private final String name; + + SSLScope(String name) { + this.name = name; + } + + // Note: the SSLScope name is case-insensitive. + public static SSLScope nameOf(String scopeName) { + for (SSLScope scope : SSLScope.values()) { + if (scope.name.equalsIgnoreCase(scopeName)) { + return scope; + } + } + + return null; + } +} diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -30,6 +30,7 @@ import java.math.BigInteger; import java.net.InetAddress; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.security.Principal; import java.security.PrivateKey; import java.security.cert.X509Certificate; @@ -193,10 +194,10 @@ this.sessionId = id; this.host = hc.conContext.transport.getPeerHost(); this.port = hc.conContext.transport.getPeerPort(); - this.localSupportedSignAlgs = hc.localSupportedSignAlgs == null ? + this.localSupportedSignAlgs = hc.localSupportedCertSignAlgs == null ? Collections.emptySet() : Collections.unmodifiableCollection( - new ArrayList<>(hc.localSupportedSignAlgs)); + new ArrayList<>(hc.localSupportedCertSignAlgs)); this.serverNameIndication = hc.negotiatedServerName; this.requestedServerNames = List.copyOf(hc.getRequestedServerNames()); if (hc.sslConfig.isClientMode) { @@ -309,113 +310,90 @@ SSLSessionImpl(HandshakeContext hc, ByteBuffer buf) throws IOException { boundValues = new ConcurrentHashMap<>(); this.protocolVersion = - ProtocolVersion.valueOf(Short.toUnsignedInt(buf.getShort())); + ProtocolVersion.valueOf(Record.getInt16(buf)); // The CH session id may reset this if it's provided this.sessionId = new SessionId(true, hc.sslContext.getSecureRandom()); this.cipherSuite = - CipherSuite.valueOf(Short.toUnsignedInt(buf.getShort())); + CipherSuite.valueOf(Record.getInt16(buf)); // Local Supported signature algorithms ArrayList list = new ArrayList<>(); - int i = Byte.toUnsignedInt(buf.get()); + int i = Record.getInt8(buf); while (i-- > 0) { list.add(SignatureScheme.valueOf( - Short.toUnsignedInt(buf.getShort()))); + Record.getInt16(buf))); } this.localSupportedSignAlgs = Collections.unmodifiableCollection(list); // Peer Supported signature algorithms - i = Byte.toUnsignedInt(buf.get()); + i = Record.getInt8(buf); list.clear(); while (i-- > 0) { list.add(SignatureScheme.valueOf( - Short.toUnsignedInt(buf.getShort()))); + Record.getInt16(buf))); } this.peerSupportedSignAlgs = Collections.unmodifiableCollection(list); // PSK - byte[] b; - i = Short.toUnsignedInt(buf.getShort()); - if (i > 0) { - b = new byte[i]; - // Get algorithm string - buf.get(b, 0, i); - // Encoded length - i = Short.toUnsignedInt(buf.getShort()); - // Encoded SecretKey - b = new byte[i]; - buf.get(b); + byte[] b = Record.getBytes16(buf); + if (b.length > 0) { + b = Record.getBytes16(buf); this.preSharedKey = new SecretKeySpec(b, "TlsMasterSecret"); } else { this.preSharedKey = null; } // PSK identity - i = buf.get(); - if (i > 0) { - b = new byte[i]; - buf.get(b); + b = Record.getBytes8(buf); + if (b.length > 0) { this.pskIdentity = b; } else { this.pskIdentity = null; } // Master secret length of secret key algorithm (one byte) - i = buf.get(); - if (i > 0) { - b = new byte[i]; - // Get algorithm string - buf.get(b, 0, i); - // Encoded length - i = Short.toUnsignedInt(buf.getShort()); - // Encoded SecretKey - b = new byte[i]; - buf.get(b); + b = Record.getBytes8(buf); + if (b.length > 0) { + b = Record.getBytes16(buf); this.masterSecret = new SecretKeySpec(b, "TlsMasterSecret"); } else { this.masterSecret = null; } + // Use extended master secret - this.useExtendedMasterSecret = (buf.get() != 0); + this.useExtendedMasterSecret = (Record.getInt8(buf) != 0); // Identification Protocol - i = buf.get(); - if (i == 0) { + b = Record.getBytes8(buf); + if (b.length == 0) { identificationProtocol = null; } else { - b = new byte[i]; - buf.get(b); identificationProtocol = new String(b); } // SNI - i = buf.get(); // length - if (i == 0) { + b = Record.getBytes8(buf); + if (b.length == 0) { serverNameIndication = null; } else { - b = new byte[i]; - buf.get(b, 0, b.length); serverNameIndication = new SNIHostName(b); } // List of SNIServerName - int len = Short.toUnsignedInt(buf.getShort()); + int len = Record.getInt16(buf); if (len == 0) { this.requestedServerNames = Collections.emptyList(); } else { requestedServerNames = new ArrayList<>(); while (len > 0) { - int l = buf.get(); - b = new byte[l]; - buf.get(b, 0, l); + b = Record.getBytes8(buf); requestedServerNames.add(new SNIHostName(new String(b))); len--; } } - maximumPacketSize = buf.getInt(); negotiatedMaxFragLen = buf.getInt(); @@ -425,31 +403,28 @@ // Get Buffer sizes // Status Response - len = Short.toUnsignedInt(buf.getShort()); + len = Record.getInt16(buf); if (len == 0) { statusResponses = Collections.emptyList(); } else { statusResponses = new ArrayList<>(); } while (len-- > 0) { - b = new byte[Short.toUnsignedInt(buf.getShort())]; - buf.get(b); + b = Record.getBytes16(buf); statusResponses.add(b); } // Get Peer host & port - i = Byte.toUnsignedInt(buf.get()); - if (i == 0) { + b = Record.getBytes8(buf); + if (b.length == 0) { this.host = ""; } else { - b = new byte[i]; - buf.get(b, 0, i); this.host = new String(b); } - this.port = Short.toUnsignedInt(buf.getShort()); + this.port = Record.getInt16(buf); // Peer certs - i = buf.get(); + i = Record.getInt8(buf); if (i == 0) { this.peerCerts = null; } else { @@ -468,7 +443,7 @@ } // Get local certs of PSK - switch (buf.get()) { + switch (Record.getInt8(buf)) { case 0: break; case 1: @@ -490,19 +465,13 @@ case 2: // pre-shared key // Length of pre-shared key algorithm (one byte) - i = buf.get(); - b = new byte[i]; - buf.get(b, 0 , i); + b = Record.getBytes8(buf); String alg = new String(b); - // Get length of encoding - i = Short.toUnsignedInt(buf.getShort()); // Get encoding - b = new byte[i]; - buf.get(b); + b = Record.getBytes16(buf); this.preSharedKey = new SecretKeySpec(b, alg); // Get identity len - this.pskIdentity = new byte[buf.get()]; - buf.get(pskIdentity); + this.pskIdentity = Record.getBytes8(buf); break; default: throw new SSLException("Failed local certs of session."); @@ -513,6 +482,7 @@ this.lastUsedTime = System.currentTimeMillis(); } + // Some situations we cannot provide a stateless ticket, but after it // has been negotiated boolean isStatelessable() { diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/ServerHello.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/ServerHello.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/ServerHello.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/ServerHello.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -269,13 +269,6 @@ "Not resumption, and no new session is allowed"); } - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); - } - SSLSessionImpl session = new SSLSessionImpl(shc, CipherSuite.C_NULL); session.setMaximumPacketSize(shc.sslConfig.maximumPacketSize); @@ -510,13 +503,6 @@ "Not resumption, and no new session is allowed"); } - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); - } - SSLSessionImpl session = new SSLSessionImpl(shc, CipherSuite.C_NULL); session.setMaximumPacketSize(shc.sslConfig.maximumPacketSize); @@ -938,6 +924,10 @@ "Negotiated protocol version: " + serverVersion.name); } + // Protocol version is negotiated, update locally supported + // signature schemes according to the protocol being used. + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); + // TLS 1.3 key share extension may have produced client // possessions for TLS 1.3 key exchanges. // @@ -989,6 +979,10 @@ "Negotiated protocol version: " + serverVersion.name); } + // Protocol version is negotiated, update locally supported + // signature schemes according to the protocol being used. + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); + if (serverHello.serverRandom.isVersionDowngrade(chc)) { throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, "A potential protocol version downgrade attack"); diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -354,12 +354,7 @@ return new byte[0]; } - if (chc.localSupportedSignAlgs == null) { - chc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols); - } + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); return chc.resumingSession.getPskIdentity(); } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -25,12 +25,16 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; +import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.text.MessageFormat; import java.util.Arrays; import java.util.List; import java.util.Locale; +import javax.net.ssl.SSLException; import javax.net.ssl.SSLProtocolException; import sun.security.ssl.SSLExtension.ExtensionConsumer; import sun.security.ssl.SSLExtension.SSLExtensionSpec; @@ -185,12 +189,7 @@ } // Produce the extension. - if (chc.localSupportedSignAlgs == null) { - chc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols); - } + SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); int vectorLen = SignatureScheme.sizeInRecord() * chc.localSupportedSignAlgs.size(); @@ -273,28 +272,8 @@ return; } - // update the context - List sss = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.negotiatedProtocol, - spec.signatureSchemes); - if (sss == null || sss.isEmpty()) { - throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, - "No supported signature algorithm"); - } - shc.peerRequestedSignatureSchemes = sss; - - // If no "signature_algorithms_cert" extension is present, then - // the "signature_algorithms" extension also applies to - // signatures appearing in certificates. - SignatureSchemesSpec certSpec = - (SignatureSchemesSpec)shc.handshakeExtensions.get( - SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); - if (certSpec == null) { - shc.peerRequestedCertSignSchemes = sss; - shc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); - } + updateHandshakeContext(shc, spec.signatureSchemes, + SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); if (!shc.isResumption && shc.negotiatedProtocol.useTLS13PlusSpec()) { @@ -412,17 +391,14 @@ } // Produce the extension. - List sigAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, - List.of(shc.negotiatedProtocol)); - - int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); + // localSupportedSignAlgs has been already updated when we + // set the negotiated protocol. + int vectorLen = SignatureScheme.sizeInRecord() + * shc.localSupportedSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; ByteBuffer m = ByteBuffer.wrap(extData); Record.putInt16(m, vectorLen); - for (SignatureScheme ss : sigAlgs) { + for (SignatureScheme ss : shc.localSupportedSignAlgs) { Record.putInt16(m, ss.id); } @@ -501,28 +477,8 @@ return; } - // update the context - List sss = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.negotiatedProtocol, - spec.signatureSchemes); - if (sss == null || sss.isEmpty()) { - throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, - "No supported signature algorithm"); - } - chc.peerRequestedSignatureSchemes = sss; - - // If no "signature_algorithms_cert" extension is present, then - // the "signature_algorithms" extension also applies to - // signatures appearing in certificates. - SignatureSchemesSpec certSpec = - (SignatureSchemesSpec)chc.handshakeExtensions.get( - SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); - if (certSpec == null) { - chc.peerRequestedCertSignSchemes = sss; - chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); - } + updateHandshakeContext(chc, spec.signatureSchemes, + SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); } } @@ -545,4 +501,49 @@ "received CertificateRequest handshake message"); } } + + // Updates given HandshakeContext with peer signature schemes. + private static void updateHandshakeContext(HandshakeContext hc, + int[] signatureSchemes, SSLExtension signatureAlgorithmsCertExt) + throws SSLException { + List handshakeSS = + SignatureScheme.getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + hc.negotiatedProtocol, + signatureSchemes, + HANDSHAKE_SCOPE); + + if (handshakeSS.isEmpty()) { + throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No supported signature algorithm"); + } + + hc.peerRequestedSignatureSchemes = handshakeSS; + + // If no "signature_algorithms_cert" extension is present, then + // the "signature_algorithms" extension also applies to + // signatures appearing in certificates. + SignatureSchemesSpec certSpec = + (SignatureSchemesSpec) hc.handshakeExtensions.get( + signatureAlgorithmsCertExt); + + if (certSpec == null) { + List certSS = + SignatureScheme.getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + hc.negotiatedProtocol, + signatureSchemes, + CERTIFICATE_SCOPE); + + if (certSS.isEmpty()) { + throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No supported signature algorithm"); + } + + hc.peerRequestedCertSignSchemes = certSS; + hc.handshakeSession.setPeerSupportedSignatureAlgorithms(certSS); + } + } } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -35,7 +35,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -218,10 +217,17 @@ } } - // performance optimization - private static final Set SIGNATURE_PRIMITIVE_SET = - Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); + // Handshake signature scope. + static final Set HANDSHAKE_SCOPE = + Set.of(SSLScope.HANDSHAKE_SIGNATURE); + + // Certificate signature scope. + static final Set CERTIFICATE_SCOPE = + Set.of(SSLScope.CERTIFICATE_SIGNATURE); + // Non-TLS specific SIGNATURE CryptoPrimitive. + private static final Set SIGNATURE_PRIMITIVE_SET = + Set.of(CryptoPrimitive.SIGNATURE); SignatureScheme(int id, String name, String algorithm, String keyAlgorithm, @@ -355,24 +361,56 @@ return 2; } - private boolean isPermitted(AlgorithmConstraints constraints) { - return constraints.permits(SIGNATURE_PRIMITIVE_SET, - this.name, null) && - constraints.permits(SIGNATURE_PRIMITIVE_SET, - this.keyAlgorithm, null) && - constraints.permits(SIGNATURE_PRIMITIVE_SET, - this.algorithm, (signAlgParams != null ? - signAlgParams.parameters : null)) && - (namedGroup == null || - namedGroup.isPermitted(constraints)); + private boolean isPermitted( + SSLAlgorithmConstraints constraints, Set scopes) { + return constraints.permits(this.name, scopes) + && constraints.permits(this.keyAlgorithm, scopes) + && constraints.permits(this.algorithm, scopes) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.name, null) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.keyAlgorithm, null) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.algorithm, + (signAlgParams != null ? signAlgParams.parameters : null)) + && (namedGroup == null || namedGroup.isPermitted(constraints)); + } + + // Helper method to update all locally supported signature schemes for + // a given HandshakeContext. + static void updateHandshakeLocalSupportedAlgs(HandshakeContext hc) { + // To improve performance we only update when necessary. + // No need to do anything if we already computed the local supported + // algorithms and either there is no negotiated protocol yet or the + // only active protocol ends up to be the negotiated protocol. + if (hc.localSupportedSignAlgs != null + && hc.localSupportedCertSignAlgs != null + && (hc.negotiatedProtocol == null + || hc.activeProtocols.size() == 1)) { + return; + } + + List protocols = hc.negotiatedProtocol != null ? + List.of(hc.negotiatedProtocol) : + hc.activeProtocols; + + hc.localSupportedSignAlgs = getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + protocols, + HANDSHAKE_SCOPE); + + hc.localSupportedCertSignAlgs = getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + protocols, + CERTIFICATE_SCOPE); } // Get local supported algorithm collection complying to algorithm - // constraints. - static List getSupportedAlgorithms( + // constraints and SSL scopes. + private static List getSupportedAlgorithms( SSLConfiguration config, - AlgorithmConstraints constraints, - List activeProtocols) { + SSLAlgorithmConstraints constraints, + List activeProtocols, + Set scopes) { List supported = new LinkedList<>(); List schemesToCheck = @@ -392,14 +430,14 @@ boolean isMatch = false; for (ProtocolVersion pv : activeProtocols) { - if (ss.supportedProtocols.contains(pv)) { + if (ss.isSupportedProtocol(pv, scopes)) { isMatch = true; break; } } if (isMatch) { - if (ss.isPermitted(constraints)) { + if (ss.isPermitted(constraints, scopes)) { supported.add(ss); } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { @@ -418,8 +456,10 @@ static List getSupportedAlgorithms( SSLConfiguration config, - AlgorithmConstraints constraints, - ProtocolVersion protocolVersion, int[] algorithmIds) { + SSLAlgorithmConstraints constraints, + ProtocolVersion protocolVersion, + int[] algorithmIds, + Set scopes) { List supported = new LinkedList<>(); for (int ssid : algorithmIds) { SignatureScheme ss = SignatureScheme.valueOf(ssid); @@ -429,11 +469,9 @@ "Unsupported signature scheme: " + SignatureScheme.nameOf(ssid)); } - } else if (ss.isAvailable && - ss.supportedProtocols.contains(protocolVersion) && - (config.signatureSchemes == null || - Utilities.contains(config.signatureSchemes, ss.name)) && - ss.isPermitted(constraints)) { + } else if ((config.signatureSchemes == null + || Utilities.contains(config.signatureSchemes, ss.name)) + && ss.isAllowed(constraints, protocolVersion, scopes)) { supported.add(ss); } else { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { @@ -447,16 +485,14 @@ } static SignatureScheme getPreferableAlgorithm( - AlgorithmConstraints constraints, + SSLAlgorithmConstraints constraints, List schemes, String keyAlgorithm, ProtocolVersion version) { for (SignatureScheme ss : schemes) { - if (ss.isAvailable && - ss.handshakeSupportedProtocols.contains(version) && - keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) && - ss.isPermitted(constraints)) { + if (keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) + && ss.isAllowed(constraints, version, HANDSHAKE_SCOPE)) { return ss; } } @@ -466,7 +502,7 @@ static Map.Entry getSignerOfPreferableAlgorithm( SSLConfiguration sslConfig, - AlgorithmConstraints constraints, + SSLAlgorithmConstraints constraints, List schemes, X509Possession x509Possession, ProtocolVersion version) { @@ -482,10 +518,9 @@ keySize = Integer.MAX_VALUE; } for (SignatureScheme ss : schemes) { - if (ss.isAvailable && (keySize >= ss.minimalKeySize) && - ss.handshakeSupportedProtocols.contains(version) && + if (keySize >= ss.minimalKeySize && keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) && - ss.isPermitted(constraints)) { + ss.isAllowed(constraints, version, HANDSHAKE_SCOPE)) { if ((ss.namedGroup != null) && (ss.namedGroup.spec == NamedGroupSpec.NAMED_GROUP_ECDHE)) { ECParameterSpec params = @@ -545,6 +580,26 @@ return null; } + // Returns true if this signature scheme is supported for the given + // protocol version and SSL scopes. + private boolean isSupportedProtocol( + ProtocolVersion version, Set scopes) { + if (scopes != null && scopes.equals(HANDSHAKE_SCOPE)) { + return this.handshakeSupportedProtocols.contains(version); + } else { + return this.supportedProtocols.contains(version); + } + } + + // Returns true if this signature scheme is available, supported and + // permitted for the given constraints, protocol version and SSL scopes. + private boolean isAllowed(SSLAlgorithmConstraints constraints, + ProtocolVersion version, Set scopes) { + return isAvailable + && isSupportedProtocol(version, scopes) + && isPermitted(constraints, scopes); + } + static String[] getAlgorithmNames(Collection schemes) { if (schemes != null) { ArrayList names = new ArrayList<>(schemes.size()); diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/util/DerValue.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/util/DerValue.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/util/DerValue.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/util/DerValue.java 2025-10-13 07:49:24.000000000 +0000 @@ -857,6 +857,22 @@ } /** + * Checks that the BMPString does not contain any surrogate characters, + * which are outside the Basic Multilingual Plane. + * + * @throws IOException if illegal characters are detected + */ + public void validateBMPString() throws IOException { + String bmpString = getBMPString(); + for (int i = 0; i < bmpString.length(); i++) { + if (Character.isSurrogate(bmpString.charAt(i))) { + throw new IOException( + "Illegal character in BMPString, index: " + i); + } + } + } + + /** * Reads the ASN.1 NULL value */ public void getNull() throws IOException { diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -25,6 +25,7 @@ package sun.security.util; +import sun.security.ssl.SSLScope; import sun.security.validator.Validator; import java.lang.ref.SoftReference; @@ -42,21 +43,22 @@ import java.security.spec.PSSParameterSpec; import java.time.DateTimeException; import java.time.Instant; -import java.time.ZonedDateTime; import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.Collection; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Algorithm constraints for disabled algorithms property @@ -101,6 +103,7 @@ } private final Set disabledAlgorithms; + private final List disabledPatterns; private final Constraints algorithmConstraints; private volatile SoftReference> cacheRef = new SoftReference<>(null); @@ -136,6 +139,13 @@ super(decomposer); disabledAlgorithms = getAlgorithms(propertyName); + // Support patterns only for jdk.tls.disabledAlgorithms + if (PROPERTY_TLS_DISABLED_ALGS.equals(propertyName)) { + disabledPatterns = getDisabledPatterns(); + } else { + disabledPatterns = null; + } + // Check for alias for (String s : disabledAlgorithms) { Matcher matcher = INCLUDE_PATTERN.matcher(s); @@ -175,6 +185,12 @@ return true; } + // Checks if algorithm is disabled for the given TLS scopes. + public boolean permits(String algorithm, Set scopes) { + List list = algorithmConstraints.getConstraints(algorithm); + return list == null || list.stream().allMatch(c -> c.permits(scopes)); + } + /* * Checks if the key algorithm has been disabled or constraints have been * placed on the key. @@ -424,7 +440,7 @@ denyAfterLimit = true; } else if (entry.startsWith("usage")) { String[] s = (entry.substring(5)).trim().split(" "); - c = new UsageConstraint(algorithm, s); + c = new UsageConstraint(algorithm, s, propertyName); if (debug != null) { debug.println("Constraints usage length is " + s.length); } @@ -596,6 +612,17 @@ } /** + * Check if the algorithm constraint permits the given TLS scopes. + * + * @param scopes TLS scopes + * @return 'true' if TLS scopes are allowed, + * 'false' otherwise. + */ + public boolean permits(Set scopes) { + return true; + } + + /** * Check if an algorithm constraint is permitted with a given * ConstraintsParameters. * @@ -772,14 +799,49 @@ /* * The usage constraint is for the "usage" keyword. It checks against the - * variant value in ConstraintsParameters. + * variant value in ConstraintsParameters and against TLS scopes. */ private static class UsageConstraint extends Constraint { String[] usages; + Set scopes; - UsageConstraint(String algorithm, String[] usages) { + UsageConstraint( + String algorithm, String[] usages, String propertyName) { this.algorithm = algorithm; - this.usages = usages; + + // Support TLS scopes only for jdk.tls.disabledAlgorithms property. + if (PROPERTY_TLS_DISABLED_ALGS.equals(propertyName)) { + for (String usage : usages) { + SSLScope scope = SSLScope.nameOf(usage); + + if (scope != null) { + if (this.scopes == null) { + this.scopes = new HashSet<>(usages.length); + } + this.scopes.add(scope); + } else { + this.usages = usages; + } + } + + if (this.scopes != null && this.usages != null) { + throw new IllegalArgumentException( + "Can't mix TLS protocol specific constraints" + + " with other usage constraints"); + } + + } else { + this.usages = usages; + } + } + + @Override + public boolean permits(Set scopes) { + if (this.scopes == null || scopes == null) { + return true; + } + + return Collections.disjoint(this.scopes, scopes); } @Override @@ -967,11 +1029,48 @@ if (result != null) { return result; } - result = checkAlgorithm(disabledAlgorithms, algorithm, decomposer); + // We won't check patterns if algorithm check fails. + result = checkAlgorithm(disabledAlgorithms, algorithm, decomposer) + && checkDisabledPatterns(algorithm); cache.put(algorithm, result); return result; } + private boolean checkDisabledPatterns(final String algorithm) { + return disabledPatterns == null || disabledPatterns.stream().noneMatch( + p -> p.matcher(algorithm).matches()); + } + + private List getDisabledPatterns() { + List ret = null; + List patternStrings = new ArrayList<>(4); + + for (String p : disabledAlgorithms) { + if (p.contains("*")) { + if (!p.startsWith("TLS_")) { + throw new IllegalArgumentException( + "Wildcard pattern must start with \"TLS_\""); + } + patternStrings.add(p); + } + } + + if (!patternStrings.isEmpty()) { + ret = new ArrayList<>(patternStrings.size()); + + for (String p : patternStrings) { + // Exclude patterns from algorithm code flow. + disabledAlgorithms.remove(p); + + // Ignore all regex characters but asterisk. + ret.add(Pattern.compile( + "^\\Q" + p.replace("*", "\\E.*\\Q") + "\\E$")); + } + } + + return ret; + } + /* * This constraint is used for the complete disabling of the algorithm. */ diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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 @@ -71,19 +71,7 @@ // OU=(c) 1999 Entrust.net Limited, // OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), // O=Entrust.net - "6DC47172E01CBCB0BF62580D895FE2B8AC9AD4F873801E0C10B9C837D21EB177", - // cacerts alias: affirmtrustcommercialca - // DN: CN=AffirmTrust Commercial, O=AffirmTrust, C=US - "0376AB1D54C5F9803CE4B2E201A0EE7EEF7B57B636E8A93C9B8D4860C96F5FA7", - // cacerts alias: affirmtrustnetworkingca - // DN: CN=AffirmTrust Networking, O=AffirmTrust, C=US - "0A81EC5A929777F145904AF38D5D509F66B5E2C58FCDB531058B0E17F3F0B41B", - // cacerts alias: affirmtrustpremiumca - // DN: CN=AffirmTrust Premium, O=AffirmTrust, C=US - "70A73F7F376B60074248904534B11482D5BF0E698ECC498DF52577EBF2E93B9A", - // cacerts alias: affirmtrustpremiumeccca - // DN: CN=AffirmTrust Premium ECC, O=AffirmTrust, C=US - "BD71FDF6DA97E4CF62D1647ADD2581B07D79ADF8397EB4ECBA9C5E8488821423" + "6DC47172E01CBCB0BF62580D895FE2B8AC9AD4F873801E0C10B9C837D21EB177" ); // Any TLS Server certificate that is anchored by one of the Entrust diff -Nru openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/x509/AVA.java openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/x509/AVA.java --- openjdk-21-21.0.8+9/src/java.base/share/classes/sun/security/x509/AVA.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/classes/sun/security/x509/AVA.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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,10 +28,13 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Reader; +import java.nio.charset.Charset; import java.text.Normalizer; import java.util.*; +import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.charset.StandardCharsets.UTF_16BE; import sun.security.action.GetBooleanAction; import sun.security.util.*; @@ -590,6 +593,10 @@ throw new IOException("AVA, extra bytes = " + derval.data.available()); } + + if (value.tag == DerValue.tag_BMPString) { + value.validateBMPString(); + } } AVA(DerInputStream in) throws IOException { @@ -714,7 +721,8 @@ * NOTE: this implementation only emits DirectoryStrings of the * types returned by isDerString(). */ - String valStr = new String(value.getDataBytes(), UTF_8); + String valStr = + new String(value.getDataBytes(), getCharset(value, false)); /* * 2.4 (cont): If the UTF-8 string does not have any of the @@ -839,7 +847,8 @@ * NOTE: this implementation only emits DirectoryStrings of the * types returned by isDerString(). */ - String valStr = new String(value.getDataBytes(), UTF_8); + String valStr = + new String(value.getDataBytes(), getCharset(value, true)); /* * 2.4 (cont): If the UTF-8 string does not have any of the @@ -942,6 +951,39 @@ } } + /* + * Returns the charset that should be used to decode each DN string type. + * + * This method ensures that multi-byte (UTF8String and BMPString) types + * are decoded using the correct charset and the String forms represent + * the correct characters. For 8-bit ASCII-based types (PrintableString + * and IA5String), we return ISO_8859_1 rather than ASCII, so that the + * complete range of characters can be represented, as many certificates + * do not comply with the Internationalized Domain Name ACE format. + * + * NOTE: this method only supports DirectoryStrings of the types returned + * by isDerString(). + */ + private static Charset getCharset(DerValue value, boolean canonical) { + if (canonical) { + return switch (value.tag) { + case DerValue.tag_PrintableString -> ISO_8859_1; + case DerValue.tag_UTF8String -> UTF_8; + default -> throw new Error("unexpected tag: " + value.tag); + }; + } + + return switch (value.tag) { + case DerValue.tag_PrintableString, + DerValue.tag_T61String, + DerValue.tag_IA5String, + DerValue.tag_GeneralString -> ISO_8859_1; + case DerValue.tag_BMPString -> UTF_16BE; + case DerValue.tag_UTF8String -> UTF_8; + default -> throw new Error("unexpected tag: " + value.tag); + }; + } + boolean hasRFC2253Keyword() { return AVAKeyword.hasKeyword(oid, RFC2253); } diff -Nru openjdk-21-21.0.8+9/src/java.base/share/conf/security/java.security openjdk-21-21.0.9+10/src/java.base/share/conf/security/java.security --- openjdk-21-21.0.8+9/src/java.base/share/conf/security/java.security 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/conf/security/java.security 2025-10-13 07:49:24.000000000 +0000 @@ -750,6 +750,29 @@ # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # +# Additional TLS-specific syntax supported by this property: +# +# - TLS cipher suites can be disabled with this property using one or more +# "*" wildcard characters. For example, "TLS_RSA_*" disables all cipher +# suites that start with "TLS_RSA_". Only cipher suites starting with +# "TLS_" are allowed to have wildcard characters. +# +# - TLS protocol specific usage constraints are supported by this property: +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# HandshakeSignature | CertificateSignature +# +# HandshakeSignature restricts the use of the algorithm in TLS handshake +# signatures. CertificateSignature restricts the use of the algorithm in +# certificate signatures. An algorithm with this constraint cannot include +# other usage types defined in the jdk.certpath.disabledAlgorithms +# property. The usage type follows the keyword and more than one usage type +# can be specified with a whitespace delimiter. +# Example: "rsa_pkcs1_sha1 usage HandshakeSignature" +# # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # @@ -758,7 +781,7 @@ # # Example: # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048, \ -# rsa_pkcs1_sha1, secp224r1 +# rsa_pkcs1_sha1, secp224r1, TLS_RSA_* jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ ECDH diff -Nru openjdk-21-21.0.8+9/src/java.base/share/data/cacerts/affirmtrustcommercialca openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustcommercialca --- openjdk-21-21.0.8+9/src/java.base/share/data/cacerts/affirmtrustcommercialca 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustcommercialca 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -Owner: CN=AffirmTrust Commercial, O=AffirmTrust, C=US -Issuer: CN=AffirmTrust Commercial, O=AffirmTrust, C=US -Serial number: 7777062726a9b17c -Valid from: Fri Jan 29 14:06:06 GMT 2010 until: Tue Dec 31 14:06:06 GMT 2030 -Signature algorithm name: SHA256withRSA -Subject Public Key Algorithm: 2048-bit RSA key -Version: 3 ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP -Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr -ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL -MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 -yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr -VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ -nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG -XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj -vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt -Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g -N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC -nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= ------END CERTIFICATE----- diff -Nru openjdk-21-21.0.8+9/src/java.base/share/data/cacerts/affirmtrustnetworkingca openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustnetworkingca --- openjdk-21-21.0.8+9/src/java.base/share/data/cacerts/affirmtrustnetworkingca 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustnetworkingca 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -Owner: CN=AffirmTrust Networking, O=AffirmTrust, C=US -Issuer: CN=AffirmTrust Networking, O=AffirmTrust, C=US -Serial number: 7c4f04391cd4992d -Valid from: Fri Jan 29 14:08:24 GMT 2010 until: Tue Dec 31 14:08:24 GMT 2030 -Signature algorithm name: SHA1withRSA -Subject Public Key Algorithm: 2048-bit RSA key -Version: 3 ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y -YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua -kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL -QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp -6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG -yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i -QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO -tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu -QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ -Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u -olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 -x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= ------END CERTIFICATE----- diff -Nru openjdk-21-21.0.8+9/src/java.base/share/data/cacerts/affirmtrustpremiumca openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustpremiumca --- openjdk-21-21.0.8+9/src/java.base/share/data/cacerts/affirmtrustpremiumca 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustpremiumca 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -Owner: CN=AffirmTrust Premium, O=AffirmTrust, C=US -Issuer: CN=AffirmTrust Premium, O=AffirmTrust, C=US -Serial number: 6d8c1446b1a60aee -Valid from: Fri Jan 29 14:10:36 GMT 2010 until: Mon Dec 31 14:10:36 GMT 2040 -Signature algorithm name: SHA384withRSA -Subject Public Key Algorithm: 4096-bit RSA key -Version: 3 ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz -dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG -A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U -cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf -qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ -JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ -+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS -s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 -HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 -70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG -V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S -qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S -5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia -C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX -OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE -FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 -KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg -Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B -8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ -MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc -0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ -u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF -u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH -YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 -GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO -RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e -KeC2uAloGRwYQw== ------END CERTIFICATE----- diff -Nru openjdk-21-21.0.8+9/src/java.base/share/data/cacerts/affirmtrustpremiumeccca openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustpremiumeccca --- openjdk-21-21.0.8+9/src/java.base/share/data/cacerts/affirmtrustpremiumeccca 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/data/cacerts/affirmtrustpremiumeccca 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -Owner: CN=AffirmTrust Premium ECC, O=AffirmTrust, C=US -Issuer: CN=AffirmTrust Premium ECC, O=AffirmTrust, C=US -Serial number: 7497258ac73f7a54 -Valid from: Fri Jan 29 14:20:24 GMT 2010 until: Mon Dec 31 14:20:24 GMT 2040 -Signature algorithm name: SHA384withECDSA -Subject Public Key Algorithm: 384-bit EC (secp384r1) key -Version: 3 ------BEGIN CERTIFICATE----- -MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC -VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ -cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ -BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt -VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D -0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 -ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G -A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs -aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I -flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== ------END CERTIFICATE----- diff -Nru openjdk-21-21.0.8+9/src/java.base/share/data/currency/CurrencyData.properties openjdk-21-21.0.9+10/src/java.base/share/data/currency/CurrencyData.properties --- openjdk-21-21.0.8+9/src/java.base/share/data/currency/CurrencyData.properties 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/data/currency/CurrencyData.properties 2025-10-13 07:49:24.000000000 +0000 @@ -32,7 +32,7 @@ # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=179 +dataVersion=180 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -147,7 +147,7 @@ # BRUNEI DARUSSALAM BN=BND # BULGARIA -BG=BGN +BG=BGN;2025-12-31-22-00-00;EUR # BURKINA FASO BF=XOF # BURUNDI @@ -193,7 +193,7 @@ # CUBA CU=CUP # Cura\u00e7ao -CW=ANG;2025-04-01-04-00-00;XCG +CW=XCG # CYPRUS CY=EUR # CZECHIA @@ -510,7 +510,7 @@ # SVALBARD AND JAN MAYEN SJ=NOK # Sint Maarten (Dutch part) -SX=ANG;2025-04-01-04-00-00;XCG +SX=XCG # ESWATINI SZ=SZL # SWEDEN diff -Nru openjdk-21-21.0.8+9/src/java.base/share/data/lsrdata/language-subtag-registry.txt openjdk-21-21.0.9+10/src/java.base/share/data/lsrdata/language-subtag-registry.txt --- openjdk-21-21.0.8+9/src/java.base/share/data/lsrdata/language-subtag-registry.txt 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/data/lsrdata/language-subtag-registry.txt 2025-10-13 07:49:24.000000000 +0000 @@ -1,4 +1,4 @@ -File-Date: 2024-11-19 +File-Date: 2025-05-15 %% Type: language Subtag: aa @@ -5950,6 +5950,7 @@ %% Type: language Subtag: bql +Description: Karian Description: Bilakura Added: 2009-07-29 %% @@ -9083,6 +9084,7 @@ %% Type: language Subtag: daz +Description: Moi-Wadea Description: Dao Added: 2009-07-29 %% @@ -9290,6 +9292,8 @@ Subtag: dek Description: Dek Added: 2009-07-29 +Deprecated: 2024-12-12 +Preferred-Value: sqm %% Type: language Subtag: del @@ -14082,6 +14086,12 @@ Macrolanguage: hmn %% Type: language +Subtag: hnm +Description: Hainanese +Added: 2024-12-12 +Macrolanguage: zh +%% +Type: language Subtag: hnn Description: Hanunoo Added: 2009-07-29 @@ -16421,6 +16431,7 @@ %% Type: language Subtag: kci +Description: Ngyian Description: Kamantan Added: 2009-07-29 %% @@ -21081,6 +21092,12 @@ Added: 2009-07-29 %% Type: language +Subtag: luh +Description: Leizhou Chinese +Added: 2024-12-12 +Macrolanguage: zh +%% +Type: language Subtag: lui Description: Luiseno Added: 2005-10-16 @@ -22850,6 +22867,8 @@ %% Type: language Subtag: mmi +Description: Hember Avu +Description: Amben Description: Musar Added: 2009-07-29 %% @@ -25197,8 +25216,9 @@ %% Type: language Subtag: new -Description: Newari Description: Nepal Bhasa +Description: Newar +Description: Newari Added: 2005-10-16 %% Type: language @@ -26641,6 +26661,8 @@ Subtag: nte Description: Nathembo Added: 2009-07-29 +Deprecated: 2024-12-12 +Preferred-Value: eko %% Type: language Subtag: ntg @@ -27185,6 +27207,12 @@ Added: 2009-07-29 %% Type: language +Subtag: oak +Description: Noakhali +Description: Noakhailla +Added: 2025-05-14 +%% +Type: language Subtag: oar Description: Old Aramaic (up to 700 BCE) Description: Ancient Aramaic (up to 700 BCE) @@ -32147,6 +32175,12 @@ Added: 2009-07-29 %% Type: language +Subtag: sjc +Description: Shaojiang Chinese +Added: 2024-12-12 +Macrolanguage: zh +%% +Type: language Subtag: sjd Description: Kildin Sami Added: 2009-07-29 @@ -41302,6 +41336,11 @@ Added: 2009-07-29 %% Type: language +Subtag: ynb +Description: Yamben +Added: 2025-02-06 +%% +Type: language Subtag: ynd Description: Yandruwandha Added: 2009-07-29 @@ -43616,6 +43655,14 @@ Prefix: sgn %% Type: extlang +Subtag: hnm +Description: Hainanese +Added: 2024-12-12 +Preferred-Value: hnm +Prefix: zh +Macrolanguage: zh +%% +Type: extlang Subtag: hos Description: Ho Chi Minh City Sign Language Added: 2009-07-29 @@ -43958,6 +44005,14 @@ Macrolanguage: lv %% Type: extlang +Subtag: luh +Description: Leizhou Chinese +Added: 2024-12-12 +Preferred-Value: luh +Prefix: zh +Macrolanguage: zh +%% +Type: extlang Subtag: lvs Description: Standard Latvian Added: 2010-03-11 @@ -44393,6 +44448,14 @@ Macrolanguage: ar %% Type: extlang +Subtag: sjc +Description: Shaojiang Chinese +Added: 2024-12-12 +Preferred-Value: sjc +Prefix: zh +Macrolanguage: zh +%% +Type: extlang Subtag: slf Description: Swiss-Italian Sign Language Added: 2009-07-29 @@ -44844,6 +44907,11 @@ Added: 2005-10-16 %% Type: script +Subtag: Berf +Description: Beria Erfe +Added: 2025-02-06 +%% +Type: script Subtag: Bhks Description: Bhaiksuki Added: 2015-07-24 @@ -45132,6 +45200,12 @@ Added: 2017-08-13 %% Type: script +Subtag: Hntl +Description: Han (Traditional variant) with Latin (alias for Hant + + Latn) +Added: 2025-05-14 +%% +Type: script Subtag: Hrkt Description: Japanese syllabaries (alias for Hiragana + Katakana) Added: 2005-10-16 @@ -45636,6 +45710,12 @@ Added: 2006-07-21 %% Type: script +Subtag: Seal +Description: Seal +Description: Small Seal +Added: 2025-05-14 +%% +Type: script Subtag: Sgnw Description: SignWriting Added: 2006-10-17 @@ -47919,6 +47999,12 @@ dóu Po, Escolo Gaston Febus, and others %% Type: variant +Subtag: hanoi +Description: The Hà Ná»™i variant of Vietnamese +Added: 2025-03-10 +Prefix: vi +%% +Type: variant Subtag: hepburn Description: Hepburn romanization Added: 2009-10-01 @@ -47949,6 +48035,12 @@ Prefix: eo %% Type: variant +Subtag: huett +Description: The Huế (province Thừa Thiên) variant of Vietnamese +Added: 2025-03-10 +Prefix: vi +%% +Type: variant Subtag: ijekavsk Description: Serbian with Ijekavian pronunciation Prefix: sr @@ -48024,6 +48116,13 @@ Comments: Preferred tag is cls %% Type: variant +Subtag: leidentr +Description: Ancient Egyptian in Leiden Unified Transliteration +Added: 2025-02-06 +Prefix: egy +Comments: Recommended by the International Association of Egyptologists +%% +Type: variant Subtag: lemosin Description: Limousin Added: 2018-04-22 @@ -48068,6 +48167,19 @@ orthographic reforms %% Type: variant +Subtag: mdcegyp +Description: Ancient Egyptian hieroglyphs encoded in Manuel de Codage +Added: 2025-02-06 +Prefix: egy +%% +Type: variant +Subtag: mdctrans +Description: Ancient Egyptian transliteration encoded in Manuel de + Codage +Added: 2025-02-06 +Prefix: egy +%% +Type: variant Subtag: metelko Description: Slovene in Metelko alphabet Added: 2012-06-27 @@ -48255,6 +48367,12 @@ Comments: Supraregional Romansh written standard %% Type: variant +Subtag: saigon +Description: The Sài Gòn variant of Vietnamese +Added: 2025-03-10 +Prefix: vi +%% +Type: variant Subtag: scotland Description: Scottish Standard English Added: 2007-08-31 diff -Nru openjdk-21-21.0.8+9/src/java.base/share/native/launcher/main.c openjdk-21-21.0.9+10/src/java.base/share/native/launcher/main.c --- openjdk-21-21.0.8+9/src/java.base/share/native/launcher/main.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/native/launcher/main.c 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -110,7 +110,25 @@ } } } - JLI_CmdToArgs(GetCommandLine()); + + // Obtain the command line in UTF-16, then convert it to ANSI code page + // without the "best-fit" option + LPWSTR wcCmdline = GetCommandLineW(); + int mbSize = WideCharToMultiByte(CP_ACP, + WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR, + wcCmdline, -1, NULL, 0, NULL, NULL); + // If the call to WideCharToMultiByte() fails, it returns 0, which + // will then make the following JLI_MemAlloc() to issue exit(1) + LPSTR mbCmdline = JLI_MemAlloc(mbSize); + if (WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR, + wcCmdline, -1, mbCmdline, mbSize, NULL, NULL) == 0) { + perror("command line encoding conversion failure"); + exit(1); + } + + JLI_CmdToArgs(mbCmdline); + JLI_MemFree(mbCmdline); + margc = JLI_GetStdArgc(); // add one more to mark the end margv = (char **)JLI_MemAlloc((margc + 1) * (sizeof(char *))); diff -Nru openjdk-21-21.0.8+9/src/java.base/share/native/libjava/ub.h openjdk-21-21.0.9+10/src/java.base/share/native/libjava/ub.h --- openjdk-21-21.0.8+9/src/java.base/share/native/libjava/ub.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/native/libjava/ub.h 2025-10-13 07:49:24.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2024 SAP SE. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025 SAP SE. 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,7 +30,10 @@ * following function or method. */ #ifdef UNDEFINED_BEHAVIOR_SANITIZER -#if defined(__clang__) || defined(__GNUC__) +#if defined(__clang__) +#define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined","float-divide-by-zero"))) +#endif +#if defined(__GNUC__) && !defined(__clang__) #define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) #endif #endif diff -Nru openjdk-21-21.0.8+9/src/java.base/share/native/libjli/java.c openjdk-21-21.0.9+10/src/java.base/share/native/libjli/java.c --- openjdk-21-21.0.8+9/src/java.base/share/native/libjli/java.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/native/libjli/java.c 2025-10-13 07:49:24.000000000 +0000 @@ -598,7 +598,14 @@ ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; LEAVE(); +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wreturn-type" +#endif } +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif /* * Test if the given name is one of the class path options. diff -Nru openjdk-21-21.0.8+9/src/java.base/share/native/libverify/check_code.c openjdk-21-21.0.9+10/src/java.base/share/native/libverify/check_code.c --- openjdk-21-21.0.8+9/src/java.base/share/native/libverify/check_code.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/share/native/libverify/check_code.c 2025-10-13 07:49:24.000000000 +0000 @@ -395,7 +395,8 @@ static void initialize_exception_table(context_type *); static int instruction_length(unsigned char *iptr, unsigned char *end); -static jboolean isLegalTarget(context_type *, int offset); +static jboolean isLegalOffset(context_type *, int bci, int offset); +static jboolean isLegalTarget(context_type *, int target); static void verify_constant_pool_type(context_type *, int, unsigned); static void initialize_dataflow(context_type *); @@ -1154,9 +1155,9 @@ case JVM_OPC_goto: { /* Set the ->operand to be the instruction number of the target. */ int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2]; - int target = offset + jump; - if (!isLegalTarget(context, target)) + if (!isLegalOffset(context, offset, jump)) CCerror(context, "Illegal target of jump or branch"); + int target = offset + jump; this_idata->operand.i = code_data[target]; break; } @@ -1170,9 +1171,9 @@ int jump = (((signed char)(code[offset+1])) << 24) + (code[offset+2] << 16) + (code[offset+3] << 8) + (code[offset + 4]); - int target = offset + jump; - if (!isLegalTarget(context, target)) + if (!isLegalOffset(context, offset, jump)) CCerror(context, "Illegal target of jump or branch"); + int target = offset + jump; this_idata->operand.i = code_data[target]; break; } @@ -1211,13 +1212,16 @@ } } saved_operand = NEW(int, keys + 2); - if (!isLegalTarget(context, offset + _ck_ntohl(lpc[0]))) + int jump = _ck_ntohl(lpc[0]); + if (!isLegalOffset(context, offset, jump)) CCerror(context, "Illegal default target in switch"); - saved_operand[keys + 1] = code_data[offset + _ck_ntohl(lpc[0])]; + int target = offset + jump; + saved_operand[keys + 1] = code_data[target]; for (k = keys, lptr = &lpc[3]; --k >= 0; lptr += delta) { - int target = offset + _ck_ntohl(lptr[0]); - if (!isLegalTarget(context, target)) + jump = _ck_ntohl(lptr[0]); + if (!isLegalOffset(context, offset, jump)) CCerror(context, "Illegal branch in tableswitch"); + target = offset + jump; saved_operand[k + 1] = code_data[target]; } saved_operand[0] = keys + 1; /* number of successors */ @@ -1746,11 +1750,24 @@ /* Given the target of a branch, make sure that it's a legal target. */ static jboolean -isLegalTarget(context_type *context, int offset) +isLegalTarget(context_type *context, int target) +{ + int code_length = context->code_length; + int *code_data = context->code_data; + return (target >= 0 && target < code_length && code_data[target] >= 0); +} + +/* Given a bci and offset, make sure the offset is valid and the target is legal */ +static jboolean +isLegalOffset(context_type *context, int bci, int offset) { int code_length = context->code_length; int *code_data = context->code_data; - return (offset >= 0 && offset < code_length && code_data[offset] >= 0); + int max_offset = 65535; // JVMS 4.11 + int min_offset = -65535; + if (offset < min_offset || offset > max_offset) return JNI_FALSE; + int target = bci + offset; + return (target >= 0 && target < code_length && code_data[target] >= 0); } diff -Nru openjdk-21-21.0.8+9/src/java.base/unix/native/libjava/java_props_md.c openjdk-21-21.0.9+10/src/java.base/unix/native/libjava/java_props_md.c --- openjdk-21-21.0.8+9/src/java.base/unix/native/libjava/java_props_md.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.base/unix/native/libjava/java_props_md.c 2025-10-13 07:49:24.000000000 +0000 @@ -239,6 +239,7 @@ if (language != NULL && mapLookup(language_names, language, std_language) == 0) { *std_language = malloc(strlen(language)+1); if (*std_language == NULL) { + free(temp); free(encoding_variant); JNU_ThrowOutOfMemoryError(env, NULL); return 0; @@ -252,6 +253,7 @@ if (mapLookup(country_names, country, std_country) == 0) { *std_country = malloc(strlen(country)+1); if (*std_country == NULL) { + free(temp); free(encoding_variant); JNU_ThrowOutOfMemoryError(env, NULL); return 0; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java openjdk-21-21.0.9+10/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java --- openjdk-21-21.0.8+9/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -60,9 +60,11 @@ import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JLabel; +import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JTextArea; import javax.swing.JList; +import javax.swing.JPopupMenu; import javax.swing.JTree; import javax.swing.KeyStroke; @@ -862,6 +864,34 @@ }, c); } + private static Accessible getCurrentAccessiblePopupMenu(Accessible a, Component c) { + if (a == null) return null; + + return invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + return traversePopupMenu(a); + } + }, c); + } + + private static Accessible traversePopupMenu(Accessible a) { + // a is root level popupmenu + AccessibleContext ac = a.getAccessibleContext(); + if (ac != null) { + for (int i = 0; i < ac.getAccessibleChildrenCount(); i++) { + Accessible child = ac.getAccessibleChild(i); + if (child instanceof JMenu subMenu) { + JPopupMenu popup = subMenu.getPopupMenu(); + if (popup.isVisible()) { + return traversePopupMenu((Accessible) popup); + } + } + } + } + return a; + } + @Native private static final int JAVA_AX_ROWS = 1; @Native private static final int JAVA_AX_COLS = 2; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java openjdk-21-21.0.9+10/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java --- openjdk-21-21.0.8+9/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -64,6 +64,7 @@ import sun.awt.AWTAccessor.ComponentAccessor; import sun.awt.AWTAccessor.WindowAccessor; import sun.java2d.SurfaceData; +import sun.lwawt.LWKeyboardFocusManagerPeer; import sun.lwawt.LWLightweightFramePeer; import sun.lwawt.LWToolkit; import sun.lwawt.LWWindowPeer; @@ -1057,6 +1058,11 @@ } execute(ptr -> nativeSetEnabled(ptr, !blocked)); + + Window currFocus = LWKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow(); + if (!blocked && (target == currFocus)) { + requestWindowFocus(); + } checkBlockingAndOrder(); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m openjdk-21-21.0.9+10/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m --- openjdk-21-21.0.8+9/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 @@ -24,6 +24,10 @@ */ #import "MenuAccessibility.h" +#import "ThreadUtilities.h" +#import "sun_lwawt_macosx_CAccessibility.h" + +static jclass sjc_CAccessibility = NULL; /* * Implementing a protocol that represents menus both as submenu and as a @@ -51,4 +55,31 @@ return NULL; } +/* + * Return all non-ignored children. + */ +- (NSArray *)accessibilityChildren { + JNIEnv *env = [ThreadUtilities getJNIEnv]; + GET_CACCESSIBILITY_CLASS_RETURN(nil); + DECLARE_STATIC_METHOD_RETURN(sjm_getCurrentAccessiblePopupMenu, sjc_CAccessibility, + "getCurrentAccessiblePopupMenu", + "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;", nil); + jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, + sjm_getCurrentAccessiblePopupMenu, + fAccessible, fComponent); + + CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent + withEnv:env withView:self->fView isCurrent:YES]; + + NSArray *children = [CommonComponentAccessibility childrenOfParent:currentElement + withEnv:env + withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN + allowIgnored:NO]; + + if ([children count] == 0) { + return nil; + } else { + return children; + } +} @end diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/beans/introspect/MethodInfo.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -31,10 +31,11 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.Deque; import java.util.List; import java.util.Set; @@ -105,13 +106,16 @@ } } - // Add default methods inherited from interfaces - for (Class iface : type.getInterfaces()) { + // Add methods inherited from interfaces + Deque> ifaceDeque = new ArrayDeque<>(List.of(type.getInterfaces())); + while (!ifaceDeque.isEmpty()) { + Class iface = ifaceDeque.removeLast(); if (IGNORABLE_INTERFACES.contains(iface)) { continue; } + ifaceDeque.addAll(List.of(iface.getInterfaces())); for (Method method : iface.getMethods()) { - if (!Modifier.isAbstract(method.getModifiers())) { + if (!Modifier.isAbstract(method.getModifiers()) && !method.isBridge()) { (list = createIfNeeded(list)).add(method); } } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -78,7 +78,8 @@ } if (!isInitedToIsGetter && this.readList != null) { for (MethodInfo info : this.readList) { - if ((this.read == null) || this.read.type.isAssignableFrom(info.type)) { + if ((this.read == null) || (!info.method.isDefault() + && this.read.type.isAssignableFrom(info.type))) { this.read = info; this.type = info.type; } @@ -91,6 +92,9 @@ if (writeType == null) { this.write = info; writeType = info.type; + } else if (isParentOfIncoming(this.write, info)) { + this.write = info; + writeType = info.type; } else if (writeType.isAssignableFrom(info.type)) { if ((this.write == null) || this.write.type.isAssignableFrom(info.type)) { this.write = info; @@ -307,4 +311,16 @@ ? Collections.unmodifiableMap(map) : Collections.emptyMap(); } + + private static boolean isParentOfIncoming(MethodInfo current, MethodInfo incoming) { + if (null == current) { + return false; + } + Class currentClass = current.method.getDeclaringClass(); + Class incomingClass = incoming.method.getDeclaringClass(); + if (currentClass == incomingClass) { + return false; + } + return currentClass.isAssignableFrom(incomingClass); + } } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -26,10 +26,13 @@ package com.sun.java.swing; import java.applet.Applet; +import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; import java.awt.Stroke; import java.awt.Window; import java.awt.geom.AffineTransform; @@ -37,11 +40,16 @@ import java.util.Map; import java.util.WeakHashMap; +import javax.swing.ButtonModel; +import javax.swing.Icon; import javax.swing.JComponent; +import javax.swing.JMenu; import javax.swing.RepaintManager; import sun.awt.AppContext; import sun.awt.SunToolkit; +import sun.swing.MenuItemLayoutHelper; +import sun.swing.SwingUtilities2; import static sun.java2d.pipe.Region.clipRound; @@ -143,6 +151,119 @@ return delegate; } + public static void applyInsets(Rectangle rect, Insets insets) { + if (insets != null) { + rect.x += insets.left; + rect.y += insets.top; + rect.width -= (insets.right + rect.x); + rect.height -= (insets.bottom + rect.y); + } + } + + public static void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color holdc, Color foreground) { + if (lh.getCheckIcon() != null) { + ButtonModel model = lh.getMenuItem().getModel(); + if (model.isArmed() || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(foreground); + } else { + g.setColor(holdc); + } + if (lh.useCheckAndArrow()) { + lh.getCheckIcon().paintIcon(lh.getMenuItem(), g, + lr.getCheckRect().x, lr.getCheckRect().y); + } + g.setColor(holdc); + } + } + + public static void paintIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, Color holdc) { + if (lh.getIcon() != null) { + Icon icon; + ButtonModel model = lh.getMenuItem().getModel(); + if (!model.isEnabled()) { + icon = lh.getMenuItem().getDisabledIcon(); + } else if (model.isPressed() && model.isArmed()) { + icon = lh.getMenuItem().getPressedIcon(); + if (icon == null) { + // Use default icon + icon = lh.getMenuItem().getIcon(); + } + } else { + icon = lh.getMenuItem().getIcon(); + } + + if (icon != null) { + icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x, + lr.getIconRect().y); + g.setColor(holdc); + } + } + } + + + public static void paintAccText(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color disabledForeground, + Color acceleratorSelectionForeground, + Color acceleratorForeground) { + if (!lh.getAccText().isEmpty()) { + ButtonModel model = lh.getMenuItem().getModel(); + g.setFont(lh.getAccFontMetrics().getFont()); + if (!model.isEnabled()) { + + // paint the accText disabled + if (disabledForeground != null) { + g.setColor(disabledForeground); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x, + lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); + } else { + g.setColor(lh.getMenuItem().getBackground().brighter()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x, + lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); + g.setColor(lh.getMenuItem().getBackground().darker()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x - 1, + lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1); + } + } else { + + // paint the accText normally + if (model.isArmed() + || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(acceleratorSelectionForeground); + } else { + g.setColor(acceleratorForeground); + } + SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(), + lr.getAccRect().x, lr.getAccRect().y + + lh.getAccFontMetrics().getAscent()); + } + } + } + + public static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color foreground) { + if (lh.getArrowIcon() != null) { + ButtonModel model = lh.getMenuItem().getModel(); + if (model.isArmed() || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(foreground); + } + if (lh.useCheckAndArrow()) { + lh.getArrowIcon().paintIcon(lh.getMenuItem(), g, + lr.getArrowRect().x, lr.getArrowRect().y); + } + } + } + /** * A task which paints an unscaled border after {@code Graphics} * transforms are removed. It's used with the diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java 2025-10-13 07:49:24.000000000 +0000 @@ -313,10 +313,10 @@ // reset current tick to 0 long tick = 0; - // reset current status byte to 0 (invalid value). + // reset current running status byte to 0 (invalid value). // this should cause us to throw an InvalidMidiDataException if we don't // get a valid status byte from the beginning of the track. - int status = 0; + int runningStatus = 0; boolean endOfTrackFound = false; while (!trackFinished() && !endOfTrackFound) { @@ -333,10 +333,17 @@ // check for new status int byteValue = readUnsigned(); + int status; if (byteValue >= 0x80) { status = byteValue; + + // update running status (only for channel messages) + if ((status & 0xF0) != 0xF0) { + runningStatus = status; + } } else { - data1 = byteValue; + status = runningStatus; + data1 = byteValue; } switch (status & 0xF0) { diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java 2025-10-13 07:49:24.000000000 +0000 @@ -110,6 +110,8 @@ TextListener, InputMethodListener, HierarchyListener, HierarchyBoundsListener, MouseWheelListener { + private static final int MAX_UNBALANCED_TOP_NODES = 100; + /** * A variable in the event chain (listener-a) */ @@ -954,6 +956,7 @@ * If listener-b is null, it returns listener-a * If neither are null, then it creates and returns * a new AWTEventMulticaster instance which chains a with b. + * * @param a event listener-a * @param b event listener-b * @return the resulting listener @@ -961,7 +964,64 @@ protected static EventListener addInternal(EventListener a, EventListener b) { if (a == null) return b; if (b == null) return a; - return new AWTEventMulticaster(a, b); + AWTEventMulticaster n = new AWTEventMulticaster(a, b); + if (!needsRebalance(n)) { + return n; + } + + EventListener[] array = getListeners(n, EventListener.class); + return rebalance(array, 0, array.length - 1); + } + + /** + * Return true if the argument represents a binary tree that needs to be rebalanced. + */ + private static boolean needsRebalance(AWTEventMulticaster l) { + int level = 0; + while (true) { + // The criteria for when we need a rebalance is subjective. This method checks + // up to a given threshold of the topmost nodes of a AWTEventMulticaster. If + // they all include one leaf node, then this method returns true. This criteria + // will be met after several consecutive iterations of `addInternal(a, b)` + if (++level > MAX_UNBALANCED_TOP_NODES) { + return true; + } + if (l.a instanceof AWTEventMulticaster aMulti) { + if (l.b instanceof AWTEventMulticaster) { + // we reached a node where both children are AWTEventMulticaster: let's assume + // the current node marks the start of a well-balanced subtree + return false; + } + l = aMulti; + } else if (l.b instanceof AWTEventMulticaster bMulti) { + l = bMulti; + } else { + return false; + } + } + } + + /** + * Recursively create a balanced tree that includes a given range of EventListeners. + * + * @param array the array of the EventListeners to consult + * @param index0 the lowest index (inclusive) that the return value must include + * @param index1 the highest index (inclusive) that the return value must include. + * + * @return a balanced tree. If index0 equals index1 then this returns an EventListener from + * the array provided. Otherwise this returns an AWTEventMulticaster. + */ + private static EventListener rebalance(EventListener[] array, int index0, int index1) { + if (index0 == index1) { + return array[index0]; + } + if (index0 == index1 - 1) { + return new AWTEventMulticaster(array[index0], array[index1]); + } + int mid = (index0 + index1) / 2; + return new AWTEventMulticaster( + rebalance(array, index0, mid), + rebalance(array, mid + 1, index1)); } /** diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/java/beans/Introspector.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/java/beans/Introspector.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/java/beans/Introspector.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/java/beans/Introspector.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -1068,8 +1068,12 @@ } } if (match) { - MethodDescriptor composite = new MethodDescriptor(old, md); - methods.put(name, composite); + Class oldClass = old.getMethod().getDeclaringClass(); + Class mdClass = md.getMethod().getDeclaringClass(); + if (oldClass == mdClass || oldClass.isAssignableFrom(mdClass) || !mdClass.isAssignableFrom(oldClass)) { + MethodDescriptor composite = new MethodDescriptor(old, md); + methods.put(name, composite); + } return; } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -25,17 +25,52 @@ package javax.swing.plaf.basic; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.plaf.*; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.InputMap; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.KeyStroke; +import javax.swing.LookAndFeel; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.event.MenuDragMouseEvent; +import javax.swing.event.MenuDragMouseListener; +import javax.swing.event.MenuKeyListener; + +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentInputMapUIResource; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.MenuItemUI; +import javax.swing.plaf.UIResource; import javax.swing.text.View; -import sun.swing.*; +import com.sun.java.swing.SwingUtilities3; +import sun.swing.MenuItemCheckIconFactory; +import sun.swing.MenuItemLayoutHelper; +import sun.swing.SwingUtilities2; +import sun.swing.UIAction; + /** * BasicMenuItem implementation @@ -670,84 +705,21 @@ private void paintIcon(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color holdc) { - if (lh.getIcon() != null) { - Icon icon; - ButtonModel model = lh.getMenuItem().getModel(); - if (!model.isEnabled()) { - icon = lh.getMenuItem().getDisabledIcon(); - } else if (model.isPressed() && model.isArmed()) { - icon = lh.getMenuItem().getPressedIcon(); - if (icon == null) { - // Use default icon - icon = lh.getMenuItem().getIcon(); - } - } else { - icon = lh.getMenuItem().getIcon(); - } - - if (icon != null) { - icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x, - lr.getIconRect().y); - g.setColor(holdc); - } - } + SwingUtilities3.paintIcon(g, lh, lr, holdc); } private void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color holdc, Color foreground) { - if (lh.getCheckIcon() != null) { - ButtonModel model = lh.getMenuItem().getModel(); - if (model.isArmed() || (lh.getMenuItem() instanceof JMenu - && model.isSelected())) { - g.setColor(foreground); - } else { - g.setColor(holdc); - } - if (lh.useCheckAndArrow()) { - lh.getCheckIcon().paintIcon(lh.getMenuItem(), g, - lr.getCheckRect().x, lr.getCheckRect().y); - } - g.setColor(holdc); - } + SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground); } private void paintAccText(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr) { - if (!lh.getAccText().isEmpty()) { - ButtonModel model = lh.getMenuItem().getModel(); - g.setFont(lh.getAccFontMetrics().getFont()); - if (!model.isEnabled()) { - // *** paint the accText disabled - if (disabledForeground != null) { - g.setColor(disabledForeground); - SwingUtilities2.drawString(lh.getMenuItem(), g, - lh.getAccText(), lr.getAccRect().x, - lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); - } else { - g.setColor(lh.getMenuItem().getBackground().brighter()); - SwingUtilities2.drawString(lh.getMenuItem(), g, - lh.getAccText(), lr.getAccRect().x, - lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); - g.setColor(lh.getMenuItem().getBackground().darker()); - SwingUtilities2.drawString(lh.getMenuItem(), g, - lh.getAccText(), lr.getAccRect().x - 1, - lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1); - } - } else { - // *** paint the accText normally - if (model.isArmed() - || (lh.getMenuItem() instanceof JMenu - && model.isSelected())) { - g.setColor(acceleratorSelectionForeground); - } else { - g.setColor(acceleratorForeground); - } - SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(), - lr.getAccRect().x, lr.getAccRect().y + - lh.getAccFontMetrics().getAscent()); - } - } + SwingUtilities3.paintAccText(g, lh, lr, + disabledForeground, + acceleratorSelectionForeground, + acceleratorForeground); } private void paintText(Graphics g, MenuItemLayoutHelper lh, @@ -766,26 +738,11 @@ private void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color foreground) { - if (lh.getArrowIcon() != null) { - ButtonModel model = lh.getMenuItem().getModel(); - if (model.isArmed() || (lh.getMenuItem() instanceof JMenu - && model.isSelected())) { - g.setColor(foreground); - } - if (lh.useCheckAndArrow()) { - lh.getArrowIcon().paintIcon(lh.getMenuItem(), g, - lr.getArrowRect().x, lr.getArrowRect().y); - } - } + SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); } private void applyInsets(Rectangle rect, Insets insets) { - if(insets != null) { - rect.x += insets.left; - rect.y += insets.top; - rect.width -= (insets.right + rect.x); - rect.height -= (insets.bottom + rect.y); - } + SwingUtilities3.applyInsets(rect, insets); } /** diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 @@ -204,8 +204,9 @@ byte[] data = null; Transferable localeTransferable = null; + openClipboard(null); + try { - openClipboard(null); long[] formats = getClipboardFormats(); Long lFormat = DataTransferer.getInstance(). @@ -318,12 +319,7 @@ * @since 1.5 */ protected long[] getClipboardFormatsOpenClose() { - try { - openClipboard(null); - return getClipboardFormats(); - } finally { - closeClipboard(); - } + return getClipboardFormats(); } /** @@ -356,15 +352,7 @@ flavorListeners.add(listener); if (numberOfFlavorListeners++ == 0) { - long[] currentFormats = null; - try { - openClipboard(null); - currentFormats = getClipboardFormats(); - } catch (final IllegalStateException ignored) { - } finally { - closeClipboard(); - } - this.currentFormats = currentFormats; + this.currentFormats = getClipboardFormats(); registerClipboardViewerChecked(); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/classes/sun/font/FileFontStrike.java openjdk-21-21.0.9+10/src/java.desktop/share/classes/sun/font/FileFontStrike.java --- openjdk-21-21.0.8+9/src/java.desktop/share/classes/sun/font/FileFontStrike.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/classes/sun/font/FileFontStrike.java 2025-10-13 07:49:24.000000000 +0000 @@ -202,7 +202,6 @@ this.disposer = new FontStrikeDisposer(fileFont, desc); initGlyphCache(); pScalerContext = NullFontScaler.getNullScalerContext(); - SunFontManager.getInstance().deRegisterBadFont(fileFont); return; } /* First, see if native code should be used to create the glyph. diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/legal/harfbuzz.md openjdk-21-21.0.9+10/src/java.desktop/share/legal/harfbuzz.md --- openjdk-21-21.0.8+9/src/java.desktop/share/legal/harfbuzz.md 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/legal/harfbuzz.md 2025-10-13 07:49:24.000000000 +0000 @@ -1,4 +1,4 @@ -## Harfbuzz v10.4.0 +## Harfbuzz 11.2.0 ### Harfbuzz License diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libfontmanager/freetypeScaler.c openjdk-21-21.0.9+10/src/java.desktop/share/native/libfontmanager/freetypeScaler.c --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libfontmanager/freetypeScaler.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libfontmanager/freetypeScaler.c 2025-10-13 07:49:24.000000000 +0000 @@ -518,7 +518,6 @@ if (context == NULL) { free(context); - invalidateJavaScaler(env, scaler, NULL); return (jlong) 0; } (*env)->GetDoubleArrayRegion(env, matrix, 0, 4, dmat); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh 2025-10-13 07:49:24.000000000 +0000 @@ -949,25 +949,25 @@ hb_glyph_extents_t extents; hb_glyph_extents_t pixel_extents; - hb_blob_t *blob = reference_png (font, glyph); - - if (unlikely (blob == hb_blob_get_empty ())) + if (unlikely (!font->get_glyph_extents (glyph, &extents, false))) return false; - if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents))) + if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) return false; - if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) + hb_blob_t *blob = reference_png (font, glyph); + if (unlikely (hb_blob_is_immutable (blob))) return false; bool ret = funcs->image (data, blob, pixel_extents.width, -pixel_extents.height, HB_PAINT_IMAGE_FORMAT_PNG, - font->slant_xy, + 0.f, &extents); hb_blob_destroy (blob); + return ret; } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh 2025-10-13 07:49:24.000000000 +0000 @@ -33,6 +33,7 @@ #include "../../../hb-open-type.hh" #include "../../../hb-ot-var-common.hh" #include "../../../hb-paint.hh" +#include "../../../hb-paint-bounded.hh" #include "../../../hb-paint-extents.hh" #include "../CPAL/CPAL.hh" @@ -47,6 +48,12 @@ struct hb_paint_context_t; } +struct hb_colr_scratch_t +{ + hb_paint_bounded_context_t paint_bounded; + hb_paint_extents_context_t paint_extents; +}; + namespace OT { struct COLR; @@ -90,12 +97,27 @@ font (font_), palette ( #ifndef HB_NO_COLOR - font->face->table.CPAL->get_palette_colors (palette_) + // https://github.com/harfbuzz/harfbuzz/issues/5116 + font->face->table.CPAL->get_palette_colors (palette_ < font->face->table.CPAL->get_palette_count () ? palette_ : 0) #endif ), foreground (foreground_), instancer (instancer_) - { } + { + if (font->is_synthetic ()) + { + font = hb_font_create_sub_font (font); + hb_font_set_synthetic_bold (font, 0, 0, true); + hb_font_set_synthetic_slant (font, 0); + } + else + hb_font_reference (font); + } + + ~hb_paint_context_t () + { + hb_font_destroy (font); + } hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground) { @@ -932,9 +954,9 @@ void paint_glyph (hb_paint_context_t *c) const { TRACE_PAINT (this); - c->funcs->push_inverse_root_transform (c->data, c->font); + c->funcs->push_inverse_font_transform (c->data, c->font); c->funcs->push_clip_glyph (c->data, gid, c->font); - c->funcs->push_root_transform (c->data, c->font); + c->funcs->push_font_transform (c->data, c->font); c->recurse (this+paint); c->funcs->pop_transform (c->data); c->funcs->pop_clip (c->data); @@ -1511,10 +1533,12 @@ void paint_glyph (hb_paint_context_t *c) const { TRACE_PAINT (this); + c->funcs->push_group (c->data); c->recurse (this+backdrop); c->funcs->push_group (c->data); c->recurse (this+src); c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode); + c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); } HBUINT8 format; /* format = 32 */ @@ -1612,7 +1636,7 @@ void closurev1 (hb_colrv1_closure_context_t* c) const { switch (u.format) { - case 2: u.format2.closurev1 (c); + case 2: u.format2.closurev1 (c); return; default:return; } } @@ -2079,6 +2103,8 @@ { static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; + bool has_data () const { return has_v0_data () || version; } + bool has_v0_data () const { return numBaseGlyphs; } bool has_v1_data () const { @@ -2112,7 +2138,53 @@ { accelerator_t (hb_face_t *face) { colr = hb_sanitize_context_t ().reference_table (face); } - ~accelerator_t () { this->colr.destroy (); } + + ~accelerator_t () + { + auto *scratch = cached_scratch.get_relaxed (); + if (scratch) + { + scratch->~hb_colr_scratch_t (); + hb_free (scratch); + } + + colr.destroy (); + } + + + bool has_data () const { return colr->has_data (); } + +#ifndef HB_NO_PAINT + bool + get_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents) const + { + if (unlikely (!has_data ())) return false; + + hb_colr_scratch_t *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; + bool ret = colr->get_extents (font, glyph, extents, *scratch); + release_scratch (scratch); + return ret; + } + + bool paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *funcs, void *data, + unsigned int palette_index, + hb_color_t foreground, + bool clip = true) const + { + if (unlikely (!has_data ())) return false; + + hb_colr_scratch_t *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; + bool ret = colr->paint_glyph (font, glyph, funcs, data, palette_index, foreground, clip, *scratch); + release_scratch (scratch); + return ret; + } +#endif bool is_valid () { return colr.get_blob ()->length; } @@ -2148,7 +2220,33 @@ { return colr->get_delta_set_index_map_ptr (); } private: + + hb_colr_scratch_t *acquire_scratch () const + { + hb_colr_scratch_t *scratch = cached_scratch.get_acquire (); + + if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) + { + scratch = (hb_colr_scratch_t *) hb_calloc (1, sizeof (hb_colr_scratch_t)); + if (unlikely (!scratch)) + return nullptr; + } + + return scratch; + } + void release_scratch (hb_colr_scratch_t *scratch) const + { + if (!cached_scratch.cmpexch (nullptr, scratch)) + { + scratch->~hb_colr_scratch_t (); + hb_free (scratch); + } + } + + public: hb_blob_ptr_t colr; + private: + mutable hb_atomic_t cached_scratch; }; void closure_glyphs (hb_codepoint_t glyph, @@ -2520,7 +2618,10 @@ #ifndef HB_NO_PAINT bool - get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + get_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + hb_colr_scratch_t &scratch) const { ItemVarStoreInstancer instancer (get_var_store_ptr (), @@ -2534,10 +2635,10 @@ } auto *extents_funcs = hb_paint_extents_get_funcs (); - hb_paint_extents_context_t extents_data; - bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0)); + scratch.paint_extents.clear (); + bool ret = paint_glyph (font, glyph, extents_funcs, &scratch.paint_extents, 0, HB_COLOR(0,0,0,0), true, scratch); - hb_extents_t e = extents_data.get_extents (); + auto e = scratch.paint_extents.get_extents (); if (e.is_void ()) { extents->x_bearing = 0; @@ -2583,7 +2684,12 @@ #ifndef HB_NO_PAINT bool - paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const + paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *funcs, void *data, + unsigned int palette_index, hb_color_t foreground, + bool clip, + hb_colr_scratch_t &scratch) const { ItemVarStoreInstancer instancer (get_var_store_ptr (), get_delta_set_index_map_ptr (), @@ -2617,26 +2723,26 @@ } else { - auto *extents_funcs = hb_paint_extents_get_funcs (); - hb_paint_extents_context_t extents_data; + clip = false; + is_bounded = false; + } + + if (!is_bounded) + { + auto *bounded_funcs = hb_paint_bounded_get_funcs (); + scratch.paint_bounded.clear (); paint_glyph (font, glyph, - extents_funcs, &extents_data, + bounded_funcs, &scratch.paint_bounded, palette_index, foreground, - false); - - hb_extents_t extents = extents_data.get_extents (); - is_bounded = extents_data.is_bounded (); + false, + scratch); - c.funcs->push_clip_rectangle (c.data, - extents.xmin, - extents.ymin, - extents.xmax, - extents.ymax); + is_bounded = scratch.paint_bounded.is_bounded (); } } - c.funcs->push_root_transform (c.data, font); + c.funcs->push_font_transform (c.data, font); if (is_bounded) c.recurse (*paint); @@ -2714,9 +2820,7 @@ return; const Paint &paint = paint_offset_lists.get_paint (i); - c->funcs->push_group (c->data); c->recurse (paint); - c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); } } @@ -2728,7 +2832,7 @@ if (unlikely (!node.visit (gid))) return; - c->funcs->push_inverse_root_transform (c->data, c->font); + c->funcs->push_inverse_font_transform (c->data, c->font); if (c->funcs->color_glyph (c->data, gid, c->font)) { c->funcs->pop_transform (c->data); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh 2025-10-13 07:49:24.000000000 +0000 @@ -237,27 +237,28 @@ int x_offset = 0, y_offset = 0; unsigned int strike_ppem = 0; - hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem); hb_glyph_extents_t extents; hb_glyph_extents_t pixel_extents; - if (blob == hb_blob_get_empty ()) + if (!font->get_glyph_extents (glyph, &extents, false)) return false; - if (!hb_font_get_glyph_extents (font, glyph, &extents)) + if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) return false; - if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) + hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem); + if (hb_blob_is_immutable (blob)) return false; bool ret = funcs->image (data, blob, pixel_extents.width, -pixel_extents.height, HB_PAINT_IMAGE_FORMAT_PNG, - font->slant_xy, + 0.f, &extents); hb_blob_destroy (blob); + return ret; } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh 2025-10-13 07:49:24.000000000 +0000 @@ -104,15 +104,16 @@ if (blob == hb_blob_get_empty ()) return false; - funcs->image (data, - blob, - 0, 0, - HB_PAINT_IMAGE_FORMAT_SVG, - font->slant_xy, - nullptr); + bool ret = funcs->image (data, + blob, + 0, 0, + HB_PAINT_IMAGE_FORMAT_SVG, + 0.f, + nullptr); hb_blob_destroy (blob); - return true; + + return ret; } private: diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh 2025-10-13 07:49:24.000000000 +0000 @@ -77,7 +77,7 @@ bool intersects (const hb_set_t *glyphs) const { - if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2) + if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len)) { for (auto g : *glyphs) if (get_coverage (g) != NOT_COVERED) diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh 2025-10-13 07:49:24.000000000 +0000 @@ -120,7 +120,7 @@ bool intersects (const hb_set_t *glyphs) const { - if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2) + if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len)) { for (auto g : *glyphs) if (get_coverage (g) != NOT_COVERED) diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh 2025-10-13 07:49:24.000000000 +0000 @@ -205,20 +205,19 @@ unsigned varidx = (this+deviceTable).get_variation_index (); hb_pair_t *new_varidx_delta; - if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) - return_trace (false); + if (c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) { + uint32_t new_varidx = hb_first (*new_varidx_delta); + int delta = hb_second (*new_varidx_delta); + if (delta != 0) + { + if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } - uint32_t new_varidx = hb_first (*new_varidx_delta); - int delta = hb_second (*new_varidx_delta); - if (delta != 0) - { - if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) - return_trace (false); + if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } - if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) - return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); - if (!c->serializer->embed (deviceTable)) return_trace (false); @@ -1015,7 +1014,8 @@ hb_blob_ptr_t table; #ifndef HB_NO_GDEF_CACHE hb_vector_t mark_glyph_set_digests; - mutable hb_cache_t<21, 3, 8> glyph_props_cache; + mutable hb_cache_t<21, 3> glyph_props_cache; + static_assert (sizeof (glyph_props_cache) == 512, ""); #endif }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh 2025-10-13 07:49:24.000000000 +0000 @@ -152,8 +152,11 @@ for (unsigned i = 0; i < len; i++) propagate_attachment_offsets (pos, len, i, direction); - if (unlikely (font->slant)) + if (unlikely (font->slant_xy) && + HB_DIRECTION_IS_HORIZONTAL (direction)) { + /* Slanting shaping results is only supported for horizontal text, + * as it gets weird otherwise. */ for (unsigned i = 0; i < len; i++) if (unlikely (pos[i].y_offset)) pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh 2025-10-13 07:49:24.000000000 +0000 @@ -54,7 +54,7 @@ { auto &cov = this+coverage; - if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4) + if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len)) { for (hb_codepoint_t g : glyphs->iter()) { diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.hh 2025-10-13 07:49:24.000000000 +0000 @@ -21,6 +21,24 @@ #ifndef HB_NO_VAR_COMPOSITES +struct hb_varc_scratch_t +{ + hb_vector_t axisIndices; + hb_vector_t axisValues; + hb_glyf_scratch_t glyf_scratch; +}; + +struct hb_varc_context_t +{ + hb_font_t *font; + hb_draw_session_t *draw_session; + hb_extents_t *extents; + mutable hb_decycler_t decycler; + mutable signed edges_left; + mutable signed depth_left; + hb_varc_scratch_t &scratch; +}; + struct VarComponent { enum class flags_t : uint32_t @@ -44,41 +62,32 @@ }; HB_INTERNAL hb_ubytes_t - get_path_at (hb_font_t *font, + get_path_at (const hb_varc_context_t &c, hb_codepoint_t parent_gid, - hb_draw_session_t &draw_session, hb_array_t coords, hb_transform_t transform, hb_ubytes_t record, - hb_decycler_t *decycler, - signed *edges_left, - signed depth_left, - hb_glyf_scratch_t &scratch, VarRegionList::cache_t *cache = nullptr) const; }; struct VarCompositeGlyph { static void - get_path_at (hb_font_t *font, - hb_codepoint_t glyph, - hb_draw_session_t &draw_session, + get_path_at (const hb_varc_context_t &c, + hb_codepoint_t gid, hb_array_t coords, hb_transform_t transform, hb_ubytes_t record, - hb_decycler_t *decycler, - signed *edges_left, - signed depth_left, - hb_glyf_scratch_t &scratch, - VarRegionList::cache_t *cache = nullptr) + VarRegionList::cache_t *cache) { while (record) { const VarComponent &comp = * (const VarComponent *) (record.arrayZ); - record = comp.get_path_at (font, glyph, - draw_session, coords, transform, + record = comp.get_path_at (c, + gid, + coords, transform, record, - decycler, edges_left, depth_left, scratch, cache); + cache); } } }; @@ -92,36 +101,47 @@ static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C'); HB_INTERNAL bool - get_path_at (hb_font_t *font, - hb_codepoint_t glyph, - hb_draw_session_t &draw_session, + get_path_at (const hb_varc_context_t &c, + hb_codepoint_t gid, hb_array_t coords, - hb_transform_t transform, - hb_codepoint_t parent_glyph, - hb_decycler_t *decycler, - signed *edges_left, - signed depth_left, - hb_glyf_scratch_t &scratch) const; + hb_transform_t transform = HB_TRANSFORM_IDENTITY, + hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID, + VarRegionList::cache_t *parent_cache = nullptr) const; bool get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, - hb_glyf_scratch_t &scratch) const + hb_varc_scratch_t &scratch) const + { + hb_varc_context_t c {font, + &draw_session, + nullptr, + hb_decycler_t {}, + HB_MAX_GRAPH_EDGE_COUNT, + HB_MAX_NESTING_LEVEL, + scratch}; + + return get_path_at (c, gid, + hb_array (font->coords, font->num_coords)); + } + + bool + get_extents (hb_font_t *font, + hb_codepoint_t gid, + hb_extents_t *extents, + hb_varc_scratch_t &scratch) const { - hb_decycler_t decycler; - signed edges = HB_MAX_GRAPH_EDGE_COUNT; + hb_varc_context_t c {font, + nullptr, + extents, + hb_decycler_t {}, + HB_MAX_GRAPH_EDGE_COUNT, + HB_MAX_NESTING_LEVEL, + scratch}; - return get_path_at (font, - gid, - draw_session, - hb_array (font->coords, font->num_coords), - HB_TRANSFORM_IDENTITY, - HB_CODEPOINT_INVALID, - &decycler, - &edges, - HB_MAX_NESTING_LEVEL, - scratch); + return get_path_at (c, gid, + hb_array (font->coords, font->num_coords)); } bool sanitize (hb_sanitize_context_t *c) const @@ -150,7 +170,7 @@ auto *scratch = cached_scratch.get_relaxed (); if (scratch) { - scratch->~hb_glyf_scratch_t (); + scratch->~hb_varc_scratch_t (); hb_free (scratch); } @@ -162,34 +182,60 @@ { if (!table->has_data ()) return false; - hb_glyf_scratch_t *scratch; + auto *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; + bool ret = table->get_path (font, gid, draw_session, *scratch); + release_scratch (scratch); + return ret; + } - // Borrow the cached strach buffer. + bool + get_extents (hb_font_t *font, + hb_codepoint_t gid, + hb_glyph_extents_t *extents) const + { + if (!table->has_data ()) return false; + + hb_extents_t f_extents; + + auto *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; + bool ret = table->get_extents (font, gid, &f_extents, *scratch); + release_scratch (scratch); + + if (ret) + *extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0); + + return ret; + } + + private: + + hb_varc_scratch_t *acquire_scratch () const + { + hb_varc_scratch_t *scratch = cached_scratch.get_acquire (); + + if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) { - scratch = cached_scratch.get_acquire (); - if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) - { - scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t)); - if (unlikely (!scratch)) - return true; - } + scratch = (hb_varc_scratch_t *) hb_calloc (1, sizeof (hb_varc_scratch_t)); + if (unlikely (!scratch)) + return nullptr; } - bool ret = table->get_path (font, gid, draw_session, *scratch); - - // Put it back. + return scratch; + } + void release_scratch (hb_varc_scratch_t *scratch) const + { if (!cached_scratch.cmpexch (nullptr, scratch)) { - scratch->~hb_glyf_scratch_t (); + scratch->~hb_varc_scratch_t (); hb_free (scratch); } - - return ret; } private: hb_blob_ptr_t table; - hb_atomic_ptr_t cached_scratch; + mutable hb_atomic_t cached_scratch; }; bool has_data () const { return version.major != 0; } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh 2025-10-13 07:49:24.000000000 +0000 @@ -429,16 +429,27 @@ } public: - bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const + + bool get_extents (hb_font_t *font, + hb_codepoint_t gid, + hb_glyph_extents_t *extents) const + { return get_extents_at (font, gid, extents, hb_array (font->coords, font->num_coords)); } + + bool get_extents_at (hb_font_t *font, + hb_codepoint_t gid, + hb_glyph_extents_t *extents, + hb_array_t coords) const { if (unlikely (gid >= num_glyphs)) return false; #ifndef HB_NO_VAR - if (font->num_coords) + if (coords) { hb_glyf_scratch_t scratch; - return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true), - hb_array (font->coords, font->num_coords), + return get_points (font, + gid, + points_aggregator_t (font, extents, nullptr, true), + coords, scratch); } #endif @@ -532,7 +543,7 @@ unsigned int num_glyphs; hb_blob_ptr_t loca_table; hb_blob_ptr_t glyf_table; - hb_atomic_ptr_t cached_scratch; + mutable hb_atomic_t cached_scratch; }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh 2025-10-13 07:49:24.000000000 +0000 @@ -29,6 +29,8 @@ #include "hb-aat-layout.hh" #include "hb-aat-map.hh" +#include "hb-ot-layout-common.hh" +#include "hb-ot-layout-gdef-table.hh" #include "hb-open-type.hh" #include "hb-cache.hh" #include "hb-bit-set.hh" @@ -48,6 +50,61 @@ using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>; static_assert (sizeof (hb_aat_class_cache_t) == 256, ""); +struct hb_aat_scratch_t +{ + hb_aat_scratch_t () = default; + hb_aat_scratch_t (const hb_aat_scratch_t &) = delete; + + hb_aat_scratch_t (hb_aat_scratch_t &&o) + { + buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ()); + o.buffer_glyph_set.set_relaxed (nullptr); + } + hb_aat_scratch_t & operator = (hb_aat_scratch_t &&o) + { + buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ()); + o.buffer_glyph_set.set_relaxed (nullptr); + return *this; + } + ~hb_aat_scratch_t () + { + auto *s = buffer_glyph_set.get_relaxed (); + if (unlikely (!s)) + return; + s->fini (); + hb_free (s); + } + + hb_bit_set_t *create_buffer_glyph_set () const + { + hb_bit_set_t *s = buffer_glyph_set.get_acquire (); + if (s && buffer_glyph_set.cmpexch (s, nullptr)) + return s; + + s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t)); + if (unlikely (!s)) + return nullptr; + s->init (); + + return s; + } + void destroy_buffer_glyph_set (hb_bit_set_t *s) const + { + if (unlikely (!s)) + return; + if (buffer_glyph_set.cmpexch (nullptr, s)) + return; + s->fini (); + hb_free (s); + } + + mutable hb_atomic_t buffer_glyph_set; +}; + +enum { DELETED_GLYPH = 0xFFFF }; + +#define HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED HB_BUFFER_SCRATCH_FLAG_SHAPER0 + struct hb_aat_apply_context_t : hb_dispatch_context_t { @@ -64,10 +121,11 @@ hb_buffer_t *buffer; hb_sanitize_context_t sanitizer; const ankr *ankr_table; - const OT::GDEF *gdef_table; + const OT::GDEF &gdef; + bool has_glyph_classes; const hb_sorted_vector_t *range_flags = nullptr; bool using_buffer_glyph_set = false; - hb_bit_set_t buffer_glyph_set; + hb_bit_set_t *buffer_glyph_set = nullptr; const hb_bit_set_t *left_set = nullptr; const hb_bit_set_t *right_set = nullptr; const hb_bit_set_t *machine_glyph_set = nullptr; @@ -90,15 +148,15 @@ void setup_buffer_glyph_set () { - using_buffer_glyph_set = buffer->len >= 4; + using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set; - if (using_buffer_glyph_set) - buffer->collect_codepoints (buffer_glyph_set); + if (likely (using_buffer_glyph_set)) + buffer->collect_codepoints (*buffer_glyph_set); } bool buffer_intersects_machine () const { - if (using_buffer_glyph_set) - return buffer_glyph_set.intersects (*machine_glyph_set); + if (likely (using_buffer_glyph_set)) + return buffer_glyph_set->intersects (*machine_glyph_set); // Faster for shorter buffers. for (unsigned i = 0; i < buffer->len; i++) @@ -106,6 +164,69 @@ return true; return false; } + + template + HB_NODISCARD bool output_glyphs (unsigned int count, + const T *glyphs) + { + if (likely (using_buffer_glyph_set)) + buffer_glyph_set->add_array (glyphs, count); + for (unsigned int i = 0; i < count; i++) + { + if (glyphs[i] == DELETED_GLYPH) + { + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED; + _hb_glyph_info_set_aat_deleted (&buffer->cur()); + } + else + { +#ifndef HB_NO_OT_LAYOUT + if (has_glyph_classes) + _hb_glyph_info_set_glyph_props (&buffer->cur(), + gdef.get_glyph_props (glyphs[i])); +#endif + } + if (unlikely (!buffer->output_glyph (glyphs[i]))) return false; + } + return true; + } + + HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph) + { + if (glyph == DELETED_GLYPH) + { + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED; + _hb_glyph_info_set_aat_deleted (&buffer->cur()); + } + + if (likely (using_buffer_glyph_set)) + buffer_glyph_set->add (glyph); +#ifndef HB_NO_OT_LAYOUT + if (has_glyph_classes) + _hb_glyph_info_set_glyph_props (&buffer->cur(), + gdef.get_glyph_props (glyph)); +#endif + return buffer->replace_glyph (glyph); + } + + HB_NODISCARD bool delete_glyph () + { + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED; + _hb_glyph_info_set_aat_deleted (&buffer->cur()); + return buffer->replace_glyph (DELETED_GLYPH); + } + + void replace_glyph_inplace (unsigned i, hb_codepoint_t glyph) + { + buffer->info[i].codepoint = glyph; + if (likely (using_buffer_glyph_set)) + buffer_glyph_set->add (glyph); +#ifndef HB_NO_OT_LAYOUT + if (has_glyph_classes) + _hb_glyph_info_set_glyph_props (&buffer->info[i], + gdef.get_glyph_props (glyph)); +#endif + } }; @@ -113,8 +234,6 @@ * Lookup Table */ -enum { DELETED_GLYPH = 0xFFFF }; - template struct Lookup; template @@ -179,6 +298,7 @@ template void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const { + if (first == DELETED_GLYPH) return; if (!filter (value)) return; glyphs.add_range (first, last); } @@ -268,6 +388,7 @@ template void collect_glyphs_filtered (set_t &glyphs, const void *base, const filter_t &filter) const { + if (first == DELETED_GLYPH) return; const auto &values = base+valuesZ; for (hb_codepoint_t i = first; i <= last; i++) if (filter (values[i - first])) @@ -368,6 +489,7 @@ template void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const { + if (glyph == DELETED_GLYPH) return; if (!filter (value)) return; glyphs.add (glyph); } @@ -746,6 +868,10 @@ } // And glyphs in those classes. + + if (filter (CLASS_DELETED_GLYPH)) + glyphs.add (DELETED_GLYPH); + (this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -185,6 +185,9 @@ DEFINE_SIZE_STATIC (2); }; + static bool initiateAction (const Entry &entry) + { return entry.flags & Push; } + static bool performAction (const Entry &entry) { return entry.data.kernActionIndex != 0xFFFF; } @@ -325,8 +328,9 @@ } else if (buffer->info[idx].mask & kern_mask) { - o.x_advance += c->font->em_scale_x (v); - o.x_offset += c->font->em_scale_x (v); + auto scaled = c->font->em_scale_x (v); + o.x_advance += scaled; + o.x_offset += scaled; } } else @@ -394,10 +398,8 @@ template void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const { - set_t set; - machine.collect_glyphs (set, num_glyphs); - left_set.union_ (set); - right_set.union_ (set); + machine.collect_initial_glyphs (left_set, num_glyphs, *this); + //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning } protected: @@ -671,10 +673,8 @@ template void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const { - set_t set; - machine.collect_glyphs (set, num_glyphs); - left_set.union_ (set); - right_set.union_ (set); + machine.collect_initial_glyphs (left_set, num_glyphs, *this); + //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning } protected: @@ -921,7 +921,18 @@ * The 'kerx' Table */ -using kern_accelerator_data_t = hb_vector_t>; +struct kern_subtable_accelerator_data_t +{ + hb_bit_set_t left_set; + hb_bit_set_t right_set; + mutable hb_aat_class_cache_t class_cache; +}; + +struct kern_accelerator_data_t +{ + hb_vector_t subtable_accels; + hb_aat_scratch_t scratch; +}; template struct KerxTable @@ -985,6 +996,8 @@ { c->buffer->unsafe_to_concat (); + c->setup_buffer_glyph_set (); + typedef typename T::SubTable SubTable; bool ret = false; @@ -996,12 +1009,25 @@ { bool reverse; + auto &subtable_accel = accel_data.subtable_accels[i]; + if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation)) goto skip; if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ()) goto skip; + c->left_set = &subtable_accel.left_set; + c->right_set = &subtable_accel.right_set; + c->machine_glyph_set = &subtable_accel.left_set; + c->machine_class_cache = &subtable_accel.class_cache; + + if (!c->buffer_intersects_machine ()) + { + (void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index); + goto skip; + } + reverse = bool (st->u.header.coverage & st->u.header.Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); @@ -1028,9 +1054,6 @@ if (reverse) c->buffer->reverse (); - c->left_set = &accel_data[i].first; - c->right_set = &accel_data[i].second; - { /* See comment in sanitize() for conditional here. */ hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr); @@ -1106,9 +1129,13 @@ unsigned int count = thiz()->tableCount; for (unsigned int i = 0; i < count; i++) { - hb_bit_set_t left_set, right_set; - st->collect_glyphs (left_set, right_set, num_glyphs); - accel_data.push (hb_pair (left_set, right_set)); + auto &subtable_accel = *accel_data.subtable_accels.push (); + if (unlikely (accel_data.subtable_accels.in_error ())) + return accel_data; + + st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs); + subtable_accel.class_cache.clear (); + st = &StructAfter (*st); } @@ -1137,6 +1164,7 @@ hb_blob_ptr_t table; kern_accelerator_data_t accel_data; + hb_aat_scratch_t scratch; }; }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -30,8 +30,6 @@ #include "hb-open-type.hh" #include "hb-aat-layout-common.hh" #include "hb-ot-layout.hh" -#include "hb-ot-layout-common.hh" -#include "hb-ot-layout-gdef-table.hh" #include "hb-aat-map.hh" /* @@ -178,12 +176,6 @@ StateTableDriver driver (machine, c->face); - if (!c->buffer_intersects_machine ()) - { - (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); - return_trace (false); - } - driver.drive (&dc, c); return_trace (dc.ret); @@ -242,9 +234,7 @@ ret (false), c (c_), table (table_), - gdef (*c->gdef_table), mark_set (false), - has_glyph_classes (gdef.has_glyph_classes ()), mark (0), subs (table+table->substitutionTables) {} @@ -281,12 +271,7 @@ if (replacement) { buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len)); - hb_codepoint_t glyph = *replacement; - buffer->info[mark].codepoint = glyph; - c->buffer_glyph_set.add (glyph); - if (has_glyph_classes) - _hb_glyph_info_set_glyph_props (&buffer->info[mark], - gdef.get_glyph_props (*replacement)); + c->replace_glyph_inplace (mark, *replacement); ret = true; } @@ -312,12 +297,7 @@ } if (replacement) { - hb_codepoint_t glyph = *replacement; - buffer->info[idx].codepoint = glyph; - c->buffer_glyph_set.add (glyph); - if (has_glyph_classes) - _hb_glyph_info_set_glyph_props (&buffer->info[idx], - gdef.get_glyph_props (*replacement)); + c->replace_glyph_inplace (idx, *replacement); ret = true; } @@ -333,9 +313,7 @@ hb_aat_apply_context_t *c; const ContextualSubtable *table; private: - const OT::GDEF &gdef; bool mark_set; - bool has_glyph_classes; unsigned int mark; const UnsizedListOfOffset16To, HBUINT, void, false> &subs; }; @@ -348,12 +326,6 @@ StateTableDriver driver (machine, c->face); - if (!c->buffer_intersects_machine ()) - { - (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); - return_trace (false); - } - driver.drive (&dc, c); return_trace (dc.ret); @@ -581,7 +553,7 @@ hb_codepoint_t lig = ligatureData; DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig); - if (unlikely (!buffer->replace_glyph (lig))) return; + if (unlikely (!c->replace_glyph (lig))) return; unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u; /* Now go and delete all subsequent components. */ @@ -589,8 +561,7 @@ { DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return; - _hb_glyph_info_set_default_ignorable (&buffer->cur()); - if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return; + if (!c->delete_glyph ()) return; } if (unlikely (!buffer->move_to (lig_end))) return; @@ -624,12 +595,6 @@ StateTableDriver driver (machine, c->face); - if (!c->buffer_intersects_machine ()) - { - (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); - return_trace (false); - } - driver.drive (&dc, c); return_trace (dc.ret); @@ -665,15 +630,6 @@ { TRACE_APPLY (this); - if (!c->buffer_intersects_machine ()) - { - (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); - return_trace (false); - } - - const OT::GDEF &gdef (*c->gdef_table); - bool has_glyph_classes = gdef.has_glyph_classes (); - bool ret = false; unsigned int num_glyphs = c->face->get_num_glyphs (); @@ -703,12 +659,7 @@ const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); if (replacement) { - hb_codepoint_t glyph = *replacement; - info[i].codepoint = glyph; - c->buffer_glyph_set.add (glyph); - if (has_glyph_classes) - _hb_glyph_info_set_glyph_props (&info[i], - gdef.get_glyph_props (*replacement)); + c->replace_glyph_inplace (i, *replacement); ret = true; } } @@ -850,9 +801,7 @@ if (buffer->idx < buffer->len && !before) if (unlikely (!buffer->copy_glyph ())) return; /* TODO We ignore KashidaLike setting. */ - if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; - for (unsigned int i = 0; i < count; i++) - c->buffer_glyph_set.add (glyphs[i]); + if (unlikely (!c->output_glyphs (count, glyphs))) return; ret = true; if (buffer->idx < buffer->len && !before) buffer->skip_glyph (); @@ -881,7 +830,8 @@ if (buffer->idx < buffer->len && !before) if (unlikely (!buffer->copy_glyph ())) return; /* TODO We ignore KashidaLike setting. */ - if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; + if (unlikely (!c->output_glyphs (count, glyphs))) return; + ret = true; if (buffer->idx < buffer->len && !before) buffer->skip_glyph (); @@ -921,12 +871,6 @@ StateTableDriver driver (machine, c->face); - if (!c->buffer_intersects_machine ()) - { - (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); - return_trace (false); - } - driver.drive (&dc, c); return_trace (dc.ret); @@ -1224,6 +1168,7 @@ if (hb_none (hb_iter (c->range_flags) | hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); }))) goto skip; + c->subtable_flags = subtable_flags; c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t); c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr; @@ -1233,6 +1178,12 @@ bool (coverage & ChainSubtable::Vertical)) goto skip; + if (!c->buffer_intersects_machine ()) + { + (void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index); + goto skip; + } + /* Buffer contents is always in logical direction. Determine if * we need to reverse before applying this subtable. We reverse * back after if we did reverse indeed. @@ -1376,7 +1327,7 @@ this->chain_count = table->get_chain_count (); - this->accels = (hb_atomic_ptr_t *) hb_calloc (this->chain_count, sizeof (*accels)); + this->accels = (hb_atomic_t *) hb_calloc (this->chain_count, sizeof (*accels)); if (unlikely (!this->accels)) { this->chain_count = 0; @@ -1423,7 +1374,8 @@ hb_blob_ptr_t table; unsigned int chain_count; - hb_atomic_ptr_t *accels; + hb_atomic_t *accels; + hb_aat_scratch_t scratch; }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -31,6 +31,7 @@ #include "hb-aat-layout-common.hh" #include "hb-ot-layout.hh" #include "hb-open-type.hh" +#include "hb-ot-stat-table.hh" /* * trak -- Tracking @@ -115,7 +116,7 @@ protected: F16DOT16 track; /* Track value for this record. */ - NameID trackNameID; /* The 'name' table index for this track. + OT::NameID trackNameID; /* The 'name' table index for this track. * (a short word or phrase like "loose" * or "very tight") */ NNOffset16To> @@ -142,9 +143,9 @@ unsigned j = count - 1; // Find the two entries that track is between. - while (i + 1 < count && trackTable[i + 1].get_track_value () < track) + while (i + 1 < count && trackTable[i + 1].get_track_value () <= track) i++; - while (j > 0 && trackTable[j - 1].get_track_value () > track) + while (j > 0 && trackTable[j - 1].get_track_value () >= track) j--; // Exact match. @@ -200,6 +201,46 @@ float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE; return font->em_scalef_y ((this+vertData).get_tracking (this, ptem, track)); } + hb_position_t get_tracking (hb_font_t *font, hb_direction_t dir, float track = 0.f) const + { +#ifndef HB_NO_STYLE + if (!font->face->table.STAT->has_data ()) + return 0; + return HB_DIRECTION_IS_HORIZONTAL (dir) ? + get_h_tracking (font, track) : + get_v_tracking (font, track); +#else + return 0; +#endif + } + + bool apply (hb_aat_apply_context_t *c, float track = 0.f) const + { + TRACE_APPLY (this); + + float ptem = c->font->ptem; + if (unlikely (ptem <= 0.f)) + { + /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */ + ptem = HB_CORETEXT_DEFAULT_FONT_SIZE; + } + + hb_buffer_t *buffer = c->buffer; + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + { + hb_position_t advance_to_add = get_h_tracking (c->font, track); + foreach_grapheme (buffer, start, end) + buffer->pos[start].x_advance += advance_to_add; + } + else + { + hb_position_t advance_to_add = get_v_tracking (c->font, track); + foreach_grapheme (buffer, start, end) + buffer->pos[start].y_advance += advance_to_add; + } + + return_trace (true); + } bool sanitize (hb_sanitize_context_t *c) const { diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc 2025-10-13 07:49:24.000000000 +0000 @@ -34,7 +34,7 @@ #include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise. #include "hb-aat-layout-kerx-table.hh" #include "hb-aat-layout-morx-table.hh" -#include "hb-aat-layout-trak-table.hh" // Just so we compile it; unused otherwise. +#include "hb-aat-layout-trak-table.hh" #include "hb-aat-ltag-table.hh" #include "hb-ot-layout-gsub-table.hh" @@ -58,13 +58,14 @@ buffer (buffer_), sanitizer (), ankr_table (&Null (AAT::ankr)), - gdef_table ( + gdef ( #ifndef HB_NO_OT_LAYOUT - face->table.GDEF->table + *face->table.GDEF->table #else - &Null (GDEF) + Null (GDEF) #endif ), + has_glyph_classes (gdef.has_glyph_classes ()), lookup_index (0) { sanitizer.init (blob); @@ -203,7 +204,7 @@ #endif -#ifndef HB_NO_AAT +#ifndef HB_NO_AAT_SHAPE /* * mort/morx/kerx/trak @@ -287,11 +288,14 @@ const hb_feature_t *features, unsigned num_features) { - hb_aat_map_builder_t builder (font->face, plan->props); - for (unsigned i = 0; i < num_features; i++) - builder.add_feature (features[i]); hb_aat_map_t map; - builder.compile (map); + if (num_features) + { + hb_aat_map_builder_t builder (font->face, plan->props); + for (unsigned i = 0; i < num_features; i++) + builder.add_feature (features[i]); + builder.compile (map); + } { auto &accel = *font->face->table.morx; @@ -300,7 +304,10 @@ { AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ()); if (!buffer->message (font, "start table morx")) return; - morx.apply (&c, map, accel); + c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set (); + morx.apply (&c, num_features ? map : plan->aat_map, accel); + accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set); + c.buffer_glyph_set = nullptr; (void) buffer->message (font, "end table morx"); return; } @@ -313,34 +320,24 @@ { AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ()); if (!buffer->message (font, "start table mort")) return; - mort.apply (&c, map, accel); + mort.apply (&c, num_features ? map : plan->aat_map, accel); (void) buffer->message (font, "end table mort"); return; } } } -void -hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer) -{ - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - hb_glyph_position_t *pos = buffer->pos; - for (unsigned int i = 0; i < count; i++) - if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH)) - pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0; -} - static bool is_deleted_glyph (const hb_glyph_info_t *info) { - return info->codepoint == AAT::DELETED_GLYPH; + return _hb_glyph_info_is_aat_deleted (info); } void hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer) { - buffer->delete_glyphs_inplace (is_deleted_glyph); + if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED) + buffer->delete_glyphs_inplace (is_deleted_glyph); } /** @@ -371,8 +368,11 @@ AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ()); if (!buffer->message (font, "start table kerx")) return; + c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set (); c.set_ankr_table (font->face->table.ankr.get ()); accel.apply (&c); + accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set); + c.buffer_glyph_set = nullptr; (void) buffer->message (font, "end table kerx"); } @@ -394,6 +394,17 @@ return face->table.trak->has_data (); } +void +hb_aat_layout_track (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + const AAT::trak& trak = *font->face->table.trak; + + AAT::hb_aat_apply_context_t c (plan, font, buffer); + trak.apply (&c); +} + /** * hb_aat_layout_get_feature_types: * @face: #hb_face_t to work upon diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh 2025-10-13 07:49:24.000000000 +0000 @@ -61,9 +61,6 @@ unsigned num_features); HB_INTERNAL void -hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer); - -HB_INTERNAL void hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer); HB_INTERNAL void @@ -71,5 +68,10 @@ hb_font_t *font, hb_buffer_t *buffer); +HB_INTERNAL void +hb_aat_layout_track (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + #endif /* HB_AAT_LAYOUT_HH */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc 2025-10-13 07:49:24.000000000 +0000 @@ -85,6 +85,11 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m) { /* Compute active features per range, and compile each. */ + if (!features.length) + { + hb_aat_layout_compile_map (this, &m); + return; + } /* Sort features by start/end events. */ hb_vector_t feature_events; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh 2025-10-13 07:49:24.000000000 +0000 @@ -80,15 +80,14 @@ #include -#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel) #define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire) #define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release) -#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) -#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_relaxed)) -#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_release)) -#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_relaxed)) -#define hb_atomic_int_impl_get(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_acquire)) +#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) +#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_relaxed)) +#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_release)) +#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_relaxed)) +#define hb_atomic_int_impl_get(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_acquire)) #define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast *> (P)->store ((V), std::memory_order_relaxed)) #define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast const *> (P)->load (std::memory_order_relaxed)) @@ -149,68 +148,53 @@ #define hb_atomic_ptr_impl_get_relaxed(P) (*(P)) #endif #ifndef hb_atomic_int_impl_set -inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; } -inline void hb_atomic_int_impl_set (short *AI, short v) { _hb_memory_w_barrier (); *AI = v; } +template +inline void hb_atomic_int_impl_set (T *AI, T v) { _hb_memory_w_barrier (); *AI = v; } #endif #ifndef hb_atomic_int_impl_get -inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; } -inline short hb_atomic_int_impl_get (const short *AI) { short v = *AI; _hb_memory_r_barrier (); return v; } +template +inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrier (); return v; } #endif #ifndef hb_atomic_ptr_impl_get inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; } #endif -struct hb_atomic_short_t +template +struct hb_atomic_t { - hb_atomic_short_t () = default; - constexpr hb_atomic_short_t (short v) : v (v) {} + hb_atomic_t () = default; + constexpr hb_atomic_t (T v) : v (v) {} - hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; } - operator short () const { return get_relaxed (); } + hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; } + operator T () const { return get_relaxed (); } - void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } - void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); } - short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } - short get_acquire () const { return hb_atomic_int_impl_get (&v); } - short inc () { return hb_atomic_int_impl_add (&v, 1); } - short dec () { return hb_atomic_int_impl_add (&v, -1); } + void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } + void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); } + T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } + T get_acquire () const { return hb_atomic_int_impl_get (&v); } + T inc () { return hb_atomic_int_impl_add (&v, 1); } + T dec () { return hb_atomic_int_impl_add (&v, -1); } + + int operator ++ (int) { return inc (); } + int operator -- (int) { return dec (); } + long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; } - short v = 0; + T v = 0; }; -struct hb_atomic_int_t +template +struct hb_atomic_t { - hb_atomic_int_t () = default; - constexpr hb_atomic_int_t (int v) : v (v) {} - - hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; } - operator int () const { return get_relaxed (); } - - void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } - void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); } - int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } - int get_acquire () const { return hb_atomic_int_impl_get (&v); } - int inc () { return hb_atomic_int_impl_add (&v, 1); } - int dec () { return hb_atomic_int_impl_add (&v, -1); } - - int v = 0; -}; - -template -struct hb_atomic_ptr_t -{ - typedef hb_remove_pointer

T; - - hb_atomic_ptr_t () = default; - constexpr hb_atomic_ptr_t (T* v) : v (v) {} - hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete; + hb_atomic_t () = default; + constexpr hb_atomic_t (T* v) : v (v) {} + hb_atomic_t (const hb_atomic_t &other) = delete; void init (T* v_ = nullptr) { set_relaxed (v_); } void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } - bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } + bool cmpexch (const T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } operator bool () const { return get_acquire () != nullptr; } T * operator -> () const { return get_acquire (); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh 2025-10-13 07:49:24.000000000 +0000 @@ -77,7 +77,7 @@ bool successful = true; /* Allocations successful */ mutable unsigned int population = 0; - mutable hb_atomic_int_t last_page_lookup = 0; + mutable hb_atomic_t last_page_lookup = 0; hb_sorted_vector_t page_map; hb_vector_t pages; @@ -88,7 +88,7 @@ { if (unlikely (!successful)) return false; - if (pages.length < count && count <= 2) + if (pages.length < count && (unsigned) pages.allocated < count && count <= 2) exact_size = true; // Most sets are small and local if (unlikely (!pages.resize (count, clear, exact_size) || diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-bit-vector.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-bit-vector.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-bit-vector.hh 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-bit-vector.hh 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,195 @@ +/* + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Author(s): Behdad Esfahbod + */ + +#ifndef HB_BIT_VECTOR_HH +#define HB_BIT_VECTOR_HH + +#include "hb.hh" + +#include "hb-atomic.hh" + +struct hb_min_max_t +{ + void add (hb_codepoint_t v) { min_v = hb_min (min_v, v); max_v = hb_max (max_v, v); } + void add_range (hb_codepoint_t a, hb_codepoint_t b) + { + min_v = hb_min (min_v, a); + max_v = hb_max (max_v, b); + } + + template + void union_ (const set_t &set) + { + hb_codepoint_t set_min = set.get_min (); + if (unlikely (set_min == HB_CODEPOINT_INVALID)) + return; + hb_codepoint_t set_max = set.get_max (); + min_v = hb_min (min_v, set_min); + max_v = hb_max (max_v, set_max); + } + + hb_codepoint_t get_min () const { return min_v; } + hb_codepoint_t get_max () const { return max_v; } + + private: + hb_codepoint_t min_v = HB_CODEPOINT_INVALID; + hb_codepoint_t max_v = 0; +}; + +template +struct hb_bit_vector_t +{ + using int_t = uint64_t; + using elt_t = typename std::conditional, int_t>::type; + + hb_bit_vector_t () = delete; + hb_bit_vector_t (const hb_bit_vector_t &other) = delete; + hb_bit_vector_t &operator= (const hb_bit_vector_t &other) = delete; + + // Move + hb_bit_vector_t (hb_bit_vector_t &&other) + : min_v (other.min_v), max_v (other.max_v), count (other.count), elts (other.elts) + { + other.min_v = other.max_v = other.count = 0; + other.elts = nullptr; + } + hb_bit_vector_t &operator= (hb_bit_vector_t &&other) + { + hb_swap (min_v, other.min_v); + hb_swap (max_v, other.max_v); + hb_swap (count, other.count); + hb_swap (elts, other.elts); + return *this; + } + + hb_bit_vector_t (unsigned min_v, unsigned max_v) + : min_v (min_v), max_v (max_v) + { + if (unlikely (min_v >= max_v)) + { + min_v = max_v = count = 0; + return; + } + + unsigned num = (max_v - min_v + sizeof (int_t) * 8) / (sizeof (int_t) * 8); + elts = (elt_t *) hb_calloc (num, sizeof (int_t)); + if (unlikely (!elts)) + { + min_v = max_v = count = 0; + return; + } + + count = max_v - min_v + 1; + } + ~hb_bit_vector_t () + { + hb_free (elts); + } + + void add (hb_codepoint_t g) { elt (g) |= mask (g); } + void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } + void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); } + bool get (hb_codepoint_t g) const { return elt (g) & mask (g); } + bool has (hb_codepoint_t g) const { return get (g); } + bool may_have (hb_codepoint_t g) const { return get (g); } + + bool operator [] (hb_codepoint_t g) const { return get (g); } + bool operator () (hb_codepoint_t g) const { return get (g); } + + void add_range (hb_codepoint_t a, hb_codepoint_t b) + { + if (unlikely (!count || a > b || a < min_v || b > max_v)) + return; + + elt_t *la = &elt (a); + elt_t *lb = &elt (b); + if (la == lb) + *la |= (mask (b) << 1) - mask(a); + else + { + *la |= ~(mask (a) - 1llu); + la++; + + hb_memset (la, 0xff, (char *) lb - (char *) la); + + *lb |= ((mask (b) << 1) - 1llu); + } + } + void del_range (hb_codepoint_t a, hb_codepoint_t b) + { + if (unlikely (!count || a > b || a < min_v || b > max_v)) + return; + + elt_t *la = &elt (a); + elt_t *lb = &elt (b); + if (la == lb) + *la &= ~((mask (b) << 1llu) - mask(a)); + else + { + *la &= mask (a) - 1; + la++; + + hb_memset (la, 0, (char *) lb - (char *) la); + + *lb &= ~((mask (b) << 1) - 1llu); + } + } + void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v) + { if (v) add_range (a, b); else del_range (a, b); } + + template + void union_ (const set_t &set) + { + for (hb_codepoint_t g : set) + add (g); + } + + static const unsigned int ELT_BITS = sizeof (elt_t) * 8; + static constexpr unsigned ELT_MASK = ELT_BITS - 1; + + static constexpr elt_t zero = 0; + + elt_t &elt (hb_codepoint_t g) + { + g -= min_v; + if (unlikely (g >= count)) + return Crap(elt_t); + return elts[g / ELT_BITS]; + } + const elt_t& elt (hb_codepoint_t g) const + { + g -= min_v; + if (unlikely (g >= count)) + return Null(elt_t); + return elts[g / ELT_BITS]; + } + + static constexpr int_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); } + + hb_codepoint_t min_v = 0, max_v = 0, count = 0; + elt_t *elts = nullptr; +}; + + +#endif /* HB_BIT_VECTOR_HH */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh 2025-10-13 07:49:24.000000000 +0000 @@ -32,62 +32,68 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-json.hh" +#line 33 "hb-buffer-deserialize-json.hh" static const unsigned char _deserialize_json_trans_keys[] = { - 0u, 0u, 9u, 123u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, - 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, - 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, - 9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, - 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, - 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, - 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, - 9u, 93u, 9u, 123u, 0u, 0u, 0 + 0u, 0u, 9u, 34u, 97u, 121u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, + 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, + 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, + 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, + 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, + 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, + 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, + 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 98u, 98u, 9u, 123u, 9u, 123u, 9u, 123u, + 0 }; static const char _deserialize_json_key_spans[] = { - 0, 115, 115, 26, 21, 2, 1, 50, - 49, 10, 117, 117, 117, 1, 50, 49, - 10, 117, 117, 1, 1, 50, 49, 117, - 117, 2, 1, 50, 49, 10, 117, 117, - 1, 50, 49, 10, 117, 117, 1, 1, - 50, 49, 117, 117, 1, 50, 49, 59, - 117, 59, 117, 117, 1, 50, 49, 117, - 85, 115, 0 + 0, 26, 25, 2, 1, 50, 49, 10, + 117, 117, 85, 117, 1, 50, 49, 10, + 117, 117, 1, 1, 50, 49, 117, 117, + 2, 1, 50, 49, 10, 117, 117, 1, + 50, 49, 10, 117, 117, 1, 1, 50, + 49, 117, 117, 1, 50, 49, 59, 117, + 59, 117, 117, 1, 50, 49, 10, 117, + 1, 50, 49, 117, 1, 115, 115, 115 }; static const short _deserialize_json_index_offsets[] = { - 0, 0, 116, 232, 259, 281, 284, 286, - 337, 387, 398, 516, 634, 752, 754, 805, - 855, 866, 984, 1102, 1104, 1106, 1157, 1207, - 1325, 1443, 1446, 1448, 1499, 1549, 1560, 1678, - 1796, 1798, 1849, 1899, 1910, 2028, 2146, 2148, - 2150, 2201, 2251, 2369, 2487, 2489, 2540, 2590, - 2650, 2768, 2828, 2946, 3064, 3066, 3117, 3167, - 3285, 3371, 3487 + 0, 0, 27, 53, 56, 58, 109, 159, + 170, 288, 406, 492, 610, 612, 663, 713, + 724, 842, 960, 962, 964, 1015, 1065, 1183, + 1301, 1304, 1306, 1357, 1407, 1418, 1536, 1654, + 1656, 1707, 1757, 1768, 1886, 2004, 2006, 2008, + 2059, 2109, 2227, 2345, 2347, 2398, 2448, 2508, + 2626, 2686, 2804, 2922, 2924, 2975, 3025, 3036, + 3154, 3156, 3207, 3257, 3375, 3377, 3493, 3609 }; static const char _deserialize_json_indicies[] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 2, 1, 3, 1, 4, 5, + 1, 6, 7, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 9, 1, 8, 10, 10, 1, 11, 12, + 1, 13, 1, 13, 13, 13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 14, 1, 14, 14, + 14, 14, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 1, 2, 2, 2, - 2, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 15, 1, 1, 16, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 1, + 18, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 1, 20, 20, 20, 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 20, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -95,48 +101,41 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 3, - 1, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 4, 1, 5, 1, 6, 1, 7, 8, - 1, 9, 10, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 22, + 1, 23, 23, 23, 23, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 11, 1, 12, 13, 1, 14, 1, 14, - 14, 14, 14, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 14, 1, + 23, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 15, 1, 15, 15, 15, 15, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 15, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 16, 1, - 1, 17, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 1, 19, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 1, 21, - 21, 21, 21, 21, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 24, 1, 24, + 24, 24, 24, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 23, 1, 24, 24, 24, - 24, 24, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 25, 1, 20, 20, 20, + 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 24, 1, 1, 1, + 1, 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 4, 1, 1, 1, 1, 1, 1, 1, + 21, 1, 1, 1, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -145,43 +144,42 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 22, 1, 26, 1, 26, 26, 26, + 26, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 25, 1, 21, 21, 21, 21, 21, + 1, 1, 1, 1, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 21, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 22, 1, - 1, 1, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 27, 1, + 27, 27, 27, 27, 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 27, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 28, 1, 1, 29, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 1, 31, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 1, 33, 33, 33, + 33, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 23, - 1, 26, 1, 26, 26, 26, 26, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 27, 1, 27, 27, - 27, 27, 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 28, 1, 1, 29, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 1, - 31, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 1, 33, 33, 33, 33, 33, + 1, 35, 1, 33, 33, 33, 33, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -190,39 +188,41 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 35, - 1, 33, 33, 33, 33, 33, 1, 1, + 1, 36, 1, 37, 1, 37, 37, 37, + 37, 37, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 33, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 34, 1, 1, 1, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 38, 1, + 38, 38, 38, 38, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 38, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 39, + 40, 40, 40, 40, 40, 40, 40, 40, + 40, 1, 41, 41, 41, 41, 41, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 41, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 42, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 35, 1, 36, - 1, 37, 1, 37, 37, 37, 37, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 38, 1, 38, 38, - 38, 38, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 39, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 1, + 1, 1, 1, 1, 1, 1, 43, 1, 41, 41, 41, 41, 41, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 41, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 42, 1, 1, 1, 1, + 1, 1, 1, 42, 1, 1, 1, 44, + 44, 44, 44, 44, 44, 44, 44, 44, + 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -230,43 +230,43 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 43, 1, 45, 46, + 1, 47, 1, 47, 47, 47, 47, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 43, 1, 41, 41, - 41, 41, 41, 1, 1, 1, 1, 1, + 1, 1, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 41, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 42, 1, 1, 1, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 1, + 1, 1, 1, 1, 48, 1, 48, 48, + 48, 48, 48, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 48, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 49, 1, 1, 50, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 1, + 52, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 1, 54, 54, 54, 54, 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 54, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 43, 1, 45, 46, 1, 47, - 1, 47, 47, 47, 47, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 48, 1, 48, 48, 48, 48, - 48, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 48, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 49, 1, 1, 50, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 1, 52, 53, - 53, 53, 53, 53, 53, 53, 53, 53, + 1, 1, 1, 1, 1, 1, 1, 56, 1, 54, 54, 54, 54, 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 55, 1, 1, 1, + 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -274,44 +274,42 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 56, 1, 57, + 1, 57, 57, 57, 57, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 56, 1, 54, - 54, 54, 54, 54, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 54, 1, + 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 55, 1, 1, 1, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 58, 1, 58, 58, 58, 58, + 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 59, 1, 1, 60, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 1, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 1, 64, 64, 64, 64, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 64, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 65, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 56, 1, 57, 1, 57, - 57, 57, 57, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 58, 1, 58, 58, 58, 58, 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 58, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 59, 1, - 1, 60, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 1, 62, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 1, 64, + 1, 1, 1, 1, 1, 66, 1, 64, 64, 64, 64, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 65, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 65, 1, 1, 1, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -320,39 +318,41 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 66, 1, 64, 64, 64, - 64, 64, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 66, 1, 67, 1, 68, + 1, 68, 68, 68, 68, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 65, 1, 1, 1, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 1, 1, + 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 69, 1, 69, 69, 69, 69, + 69, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 69, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 70, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 1, 72, 72, + 72, 72, 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 73, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 66, 1, 67, 1, 68, 1, 68, - 68, 68, 68, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 69, 1, 69, 69, 69, 69, 69, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 69, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 70, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 1, 72, 72, 72, 72, + 1, 1, 74, 1, 72, 72, 72, 72, 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 73, + 1, 1, 1, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -361,71 +361,70 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 74, 1, 76, 1, 76, 76, 76, 76, + 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 74, 1, 72, 72, 72, 72, 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 77, 1, 77, + 77, 77, 77, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 72, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 73, 1, 1, - 1, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 77, 1, + 78, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 79, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 1, 82, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 83, 81, 84, 84, 84, + 84, 84, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 84, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 85, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 74, 1, - 76, 1, 76, 76, 76, 76, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 77, 1, 77, 77, 77, - 77, 77, 1, 1, 1, 1, 1, 1, + 1, 86, 1, 81, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 77, 1, 78, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 79, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 1, 82, - 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, - 81, 83, 81, 84, 84, 84, 84, 84, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 84, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 85, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 81, 1, 87, + 87, 87, 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 88, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 86, - 1, 81, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 81, 1, 87, 87, 87, + 1, 1, 1, 89, 1, 87, 87, 87, 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 88, 1, 1, 1, 1, 1, 1, 1, + 88, 1, 1, 1, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -434,118 +433,151 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 89, 1, 91, 1, 91, 91, 91, + 91, 91, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 89, 1, 87, 87, 87, 87, 87, + 1, 1, 1, 1, 91, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 87, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 88, 1, - 1, 1, 90, 90, 90, 90, 90, 90, - 90, 90, 90, 90, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 92, 1, + 92, 92, 92, 92, 92, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 92, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 93, 1, 1, 94, + 95, 95, 95, 95, 95, 95, 95, 95, + 95, 1, 23, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 1, 23, 23, 23, + 23, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 89, - 1, 91, 1, 91, 91, 91, 91, 91, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 91, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 92, 1, 92, 92, - 92, 92, 92, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 92, 1, 1, + 1, 24, 1, 97, 1, 97, 97, 97, + 97, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 93, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 1, - 87, 87, 87, 87, 87, 1, 1, 1, + 1, 1, 1, 1, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 87, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 88, 1, 1, 1, 95, - 95, 95, 95, 95, 95, 95, 95, 95, - 95, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 98, 1, + 98, 98, 98, 98, 98, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 98, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 99, + 100, 100, 100, 100, 100, 100, 100, 100, + 100, 1, 87, 87, 87, 87, 87, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 87, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 88, 1, 1, + 1, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 89, 1, + 8, 1, 102, 102, 102, 102, 102, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 102, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 103, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 89, 1, 96, 96, - 96, 96, 96, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 96, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 97, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 104, 1, 103, 103, + 103, 103, 103, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 103, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 98, 1, 2, 2, 2, 2, - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 104, 1, 25, 25, 25, 25, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 3, 1, - 1, 0 + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 104, 1, 0 }; static const char _deserialize_json_trans_targs[] = { - 1, 0, 2, 3, 3, 4, 5, 19, - 25, 38, 44, 52, 6, 13, 7, 8, - 9, 10, 12, 10, 12, 11, 3, 56, - 11, 56, 14, 15, 16, 17, 18, 17, - 18, 11, 3, 56, 20, 21, 22, 23, - 24, 11, 3, 56, 24, 26, 32, 27, - 28, 29, 30, 31, 30, 31, 11, 3, - 56, 33, 34, 35, 36, 37, 36, 37, - 11, 3, 56, 39, 40, 41, 42, 43, - 11, 3, 56, 43, 45, 46, 47, 50, - 51, 47, 48, 49, 11, 3, 56, 11, - 3, 56, 51, 53, 54, 50, 55, 55, - 56, 57, 58 + 1, 0, 2, 3, 18, 24, 37, 43, + 51, 56, 60, 4, 12, 5, 6, 7, + 8, 11, 8, 11, 9, 1, 10, 9, + 10, 63, 13, 14, 15, 16, 17, 16, + 17, 9, 1, 10, 19, 20, 21, 22, + 23, 9, 1, 10, 23, 25, 31, 26, + 27, 28, 29, 30, 29, 30, 9, 1, + 10, 32, 33, 34, 35, 36, 35, 36, + 9, 1, 10, 38, 39, 40, 41, 42, + 9, 1, 10, 42, 44, 45, 46, 49, + 50, 46, 47, 48, 9, 1, 10, 9, + 1, 10, 50, 52, 53, 54, 9, 55, + 55, 57, 58, 49, 59, 59, 61, 62, + 1 }; static const char _deserialize_json_trans_actions[] = { - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 0, 0, 3, 3, 4, - 0, 5, 0, 0, 2, 2, 2, 0, - 0, 6, 6, 7, 0, 0, 0, 2, - 2, 8, 8, 9, 0, 0, 0, 0, - 0, 2, 2, 2, 0, 0, 10, 10, - 11, 0, 0, 2, 2, 2, 0, 0, - 12, 12, 13, 0, 0, 0, 2, 2, - 14, 14, 15, 0, 0, 0, 2, 16, - 16, 0, 17, 0, 18, 18, 19, 20, - 20, 21, 17, 0, 0, 22, 22, 23, - 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 0, 0, 2, 2, 2, 0, + 0, 3, 0, 0, 1, 1, 1, 0, + 0, 4, 4, 4, 0, 0, 0, 1, + 1, 5, 5, 5, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, 6, 6, + 6, 0, 0, 1, 1, 1, 0, 0, + 7, 7, 7, 0, 0, 0, 1, 1, + 8, 8, 8, 0, 0, 0, 1, 9, + 9, 0, 10, 0, 11, 11, 11, 12, + 12, 12, 10, 0, 0, 1, 1, 1, + 0, 0, 0, 13, 13, 14, 0, 0, + 15 }; -static const int deserialize_json_start = 1; -static const int deserialize_json_first_final = 56; +static const int deserialize_json_start = 61; +static const int deserialize_json_first_final = 61; static const int deserialize_json_error = 0; -static const int deserialize_json_en_main = 1; +static const int deserialize_json_en_main = 61; -#line 111 "hb-buffer-deserialize-json.rl" +#line 115 "hb-buffer-deserialize-json.rl" static hb_bool_t @@ -565,12 +597,12 @@ hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 569 "hb-buffer-deserialize-json.hh" +#line 594 "hb-buffer-deserialize-json.hh" { cs = deserialize_json_start; } -#line 574 "hb-buffer-deserialize-json.hh" +#line 597 "hb-buffer-deserialize-json.hh" { int _slen; int _trans; @@ -595,14 +627,14 @@ goto _again; switch ( _deserialize_json_trans_actions[_trans] ) { - case 1: + case 15: #line 38 "hb-buffer-deserialize-json.rl" { hb_memset (&info, 0, sizeof (info)); hb_memset (&pos , 0, sizeof (pos )); } break; - case 5: + case 3: #line 43 "hb-buffer-deserialize-json.rl" { buffer->add_info (info); @@ -612,21 +644,21 @@ *end_ptr = p; } break; - case 2: + case 1: #line 51 "hb-buffer-deserialize-json.rl" { tok = p; } break; - case 17: + case 10: #line 55 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_glyphs ())) return false; } break; - case 23: + case 14: #line 56 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_unicode ())) return false; } break; - case 18: + case 11: #line 58 "hb-buffer-deserialize-json.rl" { /* TODO Unescape \" and \\ if found. */ @@ -636,35 +668,35 @@ return false; } break; - case 20: + case 12: #line 66 "hb-buffer-deserialize-json.rl" { if (!parse_uint (tok, p, &info.codepoint)) return false; } break; - case 8: + case 5: #line 67 "hb-buffer-deserialize-json.rl" { if (!parse_uint (tok, p, &info.cluster )) return false; } break; - case 10: + case 6: #line 68 "hb-buffer-deserialize-json.rl" { if (!parse_int (tok, p, &pos.x_offset )) return false; } break; - case 12: + case 7: #line 69 "hb-buffer-deserialize-json.rl" { if (!parse_int (tok, p, &pos.y_offset )) return false; } break; - case 3: + case 2: #line 70 "hb-buffer-deserialize-json.rl" { if (!parse_int (tok, p, &pos.x_advance)) return false; } break; - case 6: + case 4: #line 71 "hb-buffer-deserialize-json.rl" { if (!parse_int (tok, p, &pos.y_advance)) return false; } break; - case 14: + case 8: #line 72 "hb-buffer-deserialize-json.rl" { if (!parse_uint (tok, p, &info.mask )) return false; } break; - case 16: + case 9: #line 51 "hb-buffer-deserialize-json.rl" { tok = p; @@ -672,7 +704,7 @@ #line 55 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_glyphs ())) return false; } break; - case 22: + case 13: #line 51 "hb-buffer-deserialize-json.rl" { tok = p; @@ -680,109 +712,7 @@ #line 56 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_unicode ())) return false; } break; - case 19: -#line 58 "hb-buffer-deserialize-json.rl" - { - /* TODO Unescape \" and \\ if found. */ - if (!hb_font_glyph_from_string (font, - tok+1, p - tok - 2, /* Skip "" */ - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 21: -#line 66 "hb-buffer-deserialize-json.rl" - { if (!parse_uint (tok, p, &info.codepoint)) return false; } -#line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 9: -#line 67 "hb-buffer-deserialize-json.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 68 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.x_offset )) return false; } -#line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 13: -#line 69 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } -#line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 4: -#line 70 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 7: -#line 71 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 15: -#line 72 "hb-buffer-deserialize-json.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 786 "hb-buffer-deserialize-json.hh" +#line 689 "hb-buffer-deserialize-json.hh" } _again: @@ -794,12 +724,12 @@ _out: {} } -#line 132 "hb-buffer-deserialize-json.rl" +#line 136 "hb-buffer-deserialize-json.rl" *end_ptr = p; - return p == pe && *(p-1) != ']'; + return p == pe; } #endif /* HB_BUFFER_DESERIALIZE_JSON_HH */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh 2025-10-13 07:49:24.000000000 +0000 @@ -32,287 +32,344 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-text-glyphs.hh" +#line 33 "hb-buffer-deserialize-text-glyphs.hh" static const unsigned char _deserialize_text_glyphs_trans_keys[] = { - 0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, - 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 0 + 0u, 0u, 35u, 124u, 48u, 57u, 60u, 124u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, + 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 62u, 62u, + 93u, 124u, 45u, 57u, 48u, 57u, 35u, 124u, 45u, 57u, 48u, 57u, 35u, 124u, 35u, 124u, + 35u, 124u, 35u, 124u, 35u, 124u, 35u, 124u, 48u, 57u, 35u, 124u, 45u, 57u, 48u, 57u, + 44u, 44u, 45u, 57u, 48u, 57u, 35u, 124u, 35u, 124u, 44u, 57u, 35u, 124u, 43u, 124u, + 35u, 124u, 48u, 62u, 44u, 57u, 44u, 57u, 44u, 57u, 48u, 124u, 35u, 124u, 35u, 124u, + 35u, 124u, 0 }; static const char _deserialize_text_glyphs_key_spans[] = { - 0, 10, 13, 10, 13, 10, 10, 13, - 10, 1, 13, 10, 14, 82, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116 + 0, 90, 10, 65, 13, 10, 1, 13, + 10, 1, 13, 10, 1, 13, 10, 1, + 32, 13, 10, 90, 13, 10, 90, 90, + 90, 90, 90, 90, 10, 90, 13, 10, + 1, 13, 10, 90, 90, 14, 90, 82, + 90, 15, 14, 14, 14, 77, 90, 90, + 90 }; static const short _deserialize_text_glyphs_index_offsets[] = { - 0, 0, 11, 25, 36, 50, 61, 72, - 86, 97, 99, 113, 124, 139, 222, 339, - 456, 573, 690, 807, 924, 1041, 1158, 1275, - 1392, 1509, 1626 + 0, 0, 91, 102, 168, 182, 193, 195, + 209, 220, 222, 236, 247, 249, 263, 274, + 276, 309, 323, 334, 425, 439, 450, 541, + 632, 723, 814, 905, 996, 1007, 1098, 1112, + 1123, 1125, 1139, 1150, 1241, 1332, 1347, 1438, + 1521, 1612, 1628, 1643, 1658, 1673, 1751, 1842, + 1933 }; static const char _deserialize_text_glyphs_indicies[] = { - 0, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 1, 3, 1, 1, 4, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 1, 6, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 1, 8, 1, 1, - 9, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 1, 11, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 1, 13, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 1, 15, 1, 1, 16, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 1, 18, + 1, 0, 0, 0, 0, 0, 0, + 0, 2, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 5, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 0, 9, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 3, 11, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 12, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 12, + 3, 13, 3, 3, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 3, 14, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 3, 16, 3, 17, 3, 3, 18, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 1, 20, 1, 21, 1, 1, 22, - 23, 23, 23, 23, 23, 23, 23, 23, - 23, 1, 24, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 1, 20, 1, 1, - 1, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 1, 26, 26, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 26, 1, - 1, 26, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 26, 26, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 26, 1, 28, - 28, 28, 28, 28, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 28, 27, - 27, 29, 27, 27, 27, 27, 27, 27, - 27, 30, 1, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 31, 27, 27, 32, 27, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 33, 1, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 28, 27, 34, 34, 34, 34, - 34, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 34, 26, 26, 35, 26, - 26, 26, 26, 26, 26, 26, 36, 1, - 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, - 37, 26, 26, 38, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 39, - 1, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 40, - 26, 41, 41, 41, 41, 41, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 41, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 42, 1, 43, 43, - 43, 43, 43, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 43, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 44, 1, 41, 41, 41, 41, 41, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 41, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 42, 1, - 46, 46, 46, 46, 46, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 46, - 1, 1, 47, 1, 1, 1, 1, 1, - 1, 1, 1, 48, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 49, 1, 50, 50, 50, - 50, 50, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 50, 1, 1, 51, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 52, 1, 50, 50, 50, 50, 50, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 50, 1, 1, 51, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 52, 1, 46, - 46, 46, 46, 46, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 46, 1, - 1, 47, 1, 1, 1, 1, 1, 1, - 1, 1, 48, 1, 1, 1, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 49, 1, 53, 53, 53, 53, - 53, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 53, 1, 1, 54, 1, - 1, 1, 1, 1, 1, 1, 55, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 56, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 57, - 1, 58, 58, 58, 58, 58, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 58, 1, 1, 59, 1, 1, 1, 1, - 1, 1, 1, 60, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 61, 1, 58, 58, - 58, 58, 58, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 58, 1, 1, - 59, 1, 1, 1, 1, 1, 1, 1, - 60, 1, 1, 1, 1, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 61, 1, 53, 53, 53, 53, 53, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 53, 1, 1, 54, 1, 1, - 1, 1, 1, 1, 1, 55, 1, 1, - 1, 1, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 1, 1, 1, 1, - 1, 1, 56, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 57, 1, - 0 + 19, 3, 18, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 3, 20, 3, 21, + 3, 3, 22, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 3, 22, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 3, + 24, 3, 25, 3, 3, 26, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 3, + 26, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 3, 28, 3, 29, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 29, 3, 30, 3, + 3, 31, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 3, 33, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 3, 35, + 3, 3, 3, 3, 3, 3, 3, 3, + 36, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 37, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 38, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 38, 3, 39, 3, 3, 40, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 3, + 42, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 3, 44, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 45, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 46, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 46, 3, 44, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 3, 3, 45, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 46, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 46, + 3, 35, 3, 3, 3, 3, 3, 3, + 3, 3, 36, 3, 3, 3, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, + 3, 3, 37, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 38, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 38, 3, 1, 0, 0, 0, + 0, 0, 0, 0, 2, 3, 47, 0, + 0, 48, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 0, 0, 4, 5, 0, + 0, 6, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 2, + 3, 0, 0, 0, 48, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 0, 0, + 4, 5, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 2, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 5, 0, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 0, 50, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 3, + 52, 3, 3, 3, 3, 3, 3, 3, + 53, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 54, 3, 3, 3, 55, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 56, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 56, 3, 57, 3, 3, 58, 59, + 59, 59, 59, 59, 59, 59, 59, 59, + 3, 60, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 3, 62, 3, 63, 3, + 3, 64, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 3, 66, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 3, 68, + 3, 3, 3, 3, 3, 3, 3, 69, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 70, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 71, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 71, 3, 68, 3, 3, 3, 3, 3, + 3, 3, 69, 3, 3, 3, 3, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 3, 3, 70, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 71, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 71, 3, 62, 3, 3, + 3, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 3, 52, 3, 3, 3, + 3, 3, 3, 3, 53, 3, 3, 3, + 3, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 3, 3, 54, 3, 3, + 3, 55, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 56, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 56, 3, 0, + 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 0, 3, 3, 0, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 0, 3, 1, 0, 0, 0, 0, 0, + 0, 0, 2, 16, 0, 0, 0, 49, + 49, 49, 49, 49, 49, 49, 49, 49, + 49, 0, 0, 4, 5, 0, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 0, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 3, + 3, 3, 3, 28, 3, 24, 3, 3, + 3, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 3, 20, 3, 3, 3, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 3, 16, 3, 3, 3, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 3, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 3, 3, 11, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 12, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 12, 3, + 75, 74, 74, 74, 74, 74, 74, 74, + 76, 3, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 77, 78, 74, 74, 79, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 80, 81, 82, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 82, 74, 84, 83, 83, 83, 83, + 83, 83, 83, 85, 3, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 86, 87, 83, 83, + 88, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 89, 90, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 90, 83, 91, 74, + 74, 74, 74, 74, 74, 74, 92, 3, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 93, + 94, 74, 74, 95, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 81, + 96, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 96, + 74, 0 }; static const char _deserialize_text_glyphs_trans_targs[] = { - 16, 0, 18, 3, 19, 22, 19, 22, - 5, 20, 21, 20, 21, 23, 26, 8, - 9, 12, 9, 12, 10, 11, 24, 25, - 24, 25, 15, 15, 14, 1, 2, 6, - 7, 13, 15, 1, 2, 6, 7, 13, - 14, 17, 14, 17, 14, 18, 17, 1, - 4, 14, 17, 1, 14, 17, 1, 2, - 7, 14, 17, 1, 2, 14, 26 + 1, 2, 17, 0, 25, 28, 30, 39, + 47, 3, 45, 4, 47, 5, 6, 44, + 7, 8, 9, 43, 10, 11, 12, 42, + 13, 14, 15, 41, 16, 47, 18, 19, + 24, 19, 24, 2, 20, 4, 47, 21, + 22, 23, 22, 23, 2, 4, 47, 26, + 27, 40, 29, 38, 2, 17, 4, 30, + 47, 31, 32, 37, 32, 37, 33, 34, + 35, 36, 35, 36, 2, 17, 4, 47, + 38, 45, 1, 2, 17, 25, 28, 30, + 48, 39, 47, 1, 2, 17, 25, 28, + 30, 39, 47, 2, 17, 25, 28, 30, + 47 }; static const char _deserialize_text_glyphs_trans_actions[] = { - 1, 0, 1, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 1, 1, 1, - 1, 1, 0, 0, 2, 1, 1, 1, - 0, 0, 0, 4, 3, 5, 5, 5, - 5, 4, 6, 7, 7, 7, 7, 0, - 6, 8, 8, 0, 0, 0, 9, 10, - 10, 9, 11, 12, 11, 13, 14, 14, - 14, 13, 15, 16, 16, 15, 0 + 0, 1, 1, 0, 1, 1, 1, 0, + 1, 2, 2, 3, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 4, 4, 4, 4, 2, + 2, 2, 0, 0, 5, 5, 5, 0, + 0, 0, 2, 2, 6, 6, 6, 6, + 6, 2, 2, 2, 0, 0, 7, 2, + 2, 2, 0, 0, 8, 8, 8, 8, + 0, 0, 9, 10, 10, 10, 10, 10, + 9, 9, 10, 12, 13, 13, 13, 13, + 13, 12, 13, 14, 14, 14, 14, 14, + 14 }; static const char _deserialize_text_glyphs_eof_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3, 6, - 8, 0, 8, 9, 11, 11, 9, 13, - 15, 15, 13 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 11, + 0 }; -static const int deserialize_text_glyphs_start = 14; -static const int deserialize_text_glyphs_first_final = 14; +static const int deserialize_text_glyphs_start = 46; +static const int deserialize_text_glyphs_first_final = 46; static const int deserialize_text_glyphs_error = 0; -static const int deserialize_text_glyphs_en_main = 14; +static const int deserialize_text_glyphs_en_main = 46; -#line 98 "hb-buffer-deserialize-text-glyphs.rl" +#line 101 "hb-buffer-deserialize-text-glyphs.rl" static hb_bool_t @@ -322,39 +379,22 @@ const char **end_ptr, hb_font_t *font) { - const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe; + const char *p = buf, *pe = buf + buf_len, *eof = pe; /* Ensure we have positions. */ (void) hb_buffer_get_glyph_positions (buffer, nullptr); - while (p < pe && ISSPACE (*p)) - p++; - if (p < pe && *p == (buffer->len ? '|' : '[')) - *end_ptr = ++p; - - const char *end = strchr ((char *) p, ']'); - if (end) - pe = eof = end; - else - { - end = strrchr ((char *) p, '|'); - if (end) - pe = eof = end; - else - pe = eof = p; - } - const char *tok = nullptr; int cs; hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 353 "hb-buffer-deserialize-text-glyphs.hh" +#line 386 "hb-buffer-deserialize-text-glyphs.hh" { cs = deserialize_text_glyphs_start; } -#line 358 "hb-buffer-deserialize-text-glyphs.hh" +#line 389 "hb-buffer-deserialize-text-glyphs.hh" { int _slen; int _trans; @@ -379,14 +419,14 @@ goto _again; switch ( _deserialize_text_glyphs_trans_actions[_trans] ) { - case 1: -#line 51 "hb-buffer-deserialize-text-glyphs.rl" + case 2: +#line 50 "hb-buffer-deserialize-text-glyphs.rl" { tok = p; } break; - case 7: -#line 55 "hb-buffer-deserialize-text-glyphs.rl" + case 1: +#line 54 "hb-buffer-deserialize-text-glyphs.rl" { /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, @@ -395,145 +435,115 @@ return false; } break; - case 14: -#line 63 "hb-buffer-deserialize-text-glyphs.rl" + case 6: +#line 62 "hb-buffer-deserialize-text-glyphs.rl" { if (!parse_uint (tok, p, &info.cluster )) return false; } break; - case 2: -#line 64 "hb-buffer-deserialize-text-glyphs.rl" + case 7: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" { if (!parse_int (tok, p, &pos.x_offset )) return false; } break; - case 16: -#line 65 "hb-buffer-deserialize-text-glyphs.rl" + case 8: +#line 64 "hb-buffer-deserialize-text-glyphs.rl" { if (!parse_int (tok, p, &pos.y_offset )) return false; } break; - case 10: -#line 66 "hb-buffer-deserialize-text-glyphs.rl" + case 4: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" { if (!parse_int (tok, p, &pos.x_advance)) return false; } break; - case 12: -#line 67 "hb-buffer-deserialize-text-glyphs.rl" + case 5: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" { if (!parse_int (tok, p, &pos.y_advance)) return false; } break; - case 4: + case 3: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } + break; + case 9: #line 38 "hb-buffer-deserialize-text-glyphs.rl" { hb_memset (&info, 0, sizeof (info)); hb_memset (&pos , 0, sizeof (pos )); } -#line 51 "hb-buffer-deserialize-text-glyphs.rl" +#line 50 "hb-buffer-deserialize-text-glyphs.rl" { tok = p; } break; - case 6: -#line 55 "hb-buffer-deserialize-text-glyphs.rl" + case 10: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" +#line 50 "hb-buffer-deserialize-text-glyphs.rl" { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; + tok = p; } - break; - case 13: -#line 63 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" +#line 54 "hb-buffer-deserialize-text-glyphs.rl" { - buffer->add_info (info); - if (unlikely (!buffer->successful)) + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; } break; - case 15: -#line 65 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } + case 12: #line 43 "hb-buffer-deserialize-text-glyphs.rl" { - buffer->add_info (info); + buffer->add_info_and_pos (info, pos); if (unlikely (!buffer->successful)) return false; - buffer->pos[buffer->len - 1] = pos; *end_ptr = p; } - break; - case 9: -#line 66 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" +#line 38 "hb-buffer-deserialize-text-glyphs.rl" { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } - break; - case 11: -#line 67 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" +#line 50 "hb-buffer-deserialize-text-glyphs.rl" { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; + tok = p; } break; - case 8: -#line 68 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" + case 14: +#line 54 "hb-buffer-deserialize-text-glyphs.rl" { - buffer->add_info (info); - if (unlikely (!buffer->successful)) + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; } - break; - case 5: #line 38 "hb-buffer-deserialize-text-glyphs.rl" { hb_memset (&info, 0, sizeof (info)); hb_memset (&pos , 0, sizeof (pos )); } -#line 51 "hb-buffer-deserialize-text-glyphs.rl" +#line 50 "hb-buffer-deserialize-text-glyphs.rl" { tok = p; } -#line 55 "hb-buffer-deserialize-text-glyphs.rl" + break; + case 13: +#line 43 "hb-buffer-deserialize-text-glyphs.rl" { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) + buffer->add_info_and_pos (info, pos); + if (unlikely (!buffer->successful)) return false; + *end_ptr = p; } - break; - case 3: #line 38 "hb-buffer-deserialize-text-glyphs.rl" { hb_memset (&info, 0, sizeof (info)); hb_memset (&pos , 0, sizeof (pos )); } -#line 51 "hb-buffer-deserialize-text-glyphs.rl" +#line 50 "hb-buffer-deserialize-text-glyphs.rl" { tok = p; } -#line 55 "hb-buffer-deserialize-text-glyphs.rl" +#line 54 "hb-buffer-deserialize-text-glyphs.rl" { /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, @@ -541,16 +551,8 @@ &info.codepoint)) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} break; -#line 554 "hb-buffer-deserialize-text-glyphs.hh" +#line 523 "hb-buffer-deserialize-text-glyphs.hh" } _again: @@ -562,127 +564,24 @@ if ( p == eof ) { switch ( _deserialize_text_glyphs_eof_actions[cs] ) { - case 6: -#line 55 "hb-buffer-deserialize-text-glyphs.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text-glyphs.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 13: -#line 63 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 15: -#line 65 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 9: -#line 66 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; case 11: -#line 67 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 8: -#line 68 "hb-buffer-deserialize-text-glyphs.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text-glyphs.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 3: -#line 38 "hb-buffer-deserialize-text-glyphs.rl" - { - hb_memset (&info, 0, sizeof (info)); - hb_memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text-glyphs.rl" - { - tok = p; -} -#line 55 "hb-buffer-deserialize-text-glyphs.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} #line 43 "hb-buffer-deserialize-text-glyphs.rl" { - buffer->add_info (info); + buffer->add_info_and_pos (info, pos); if (unlikely (!buffer->successful)) return false; - buffer->pos[buffer->len - 1] = pos; *end_ptr = p; } break; -#line 671 "hb-buffer-deserialize-text-glyphs.hh" +#line 542 "hb-buffer-deserialize-text-glyphs.hh" } } _out: {} } -#line 136 "hb-buffer-deserialize-text-glyphs.rl" - +#line 122 "hb-buffer-deserialize-text-glyphs.rl" - if (pe < orig_pe && *pe == ']') - { - pe++; - if (p == pe) - p++; - } *end_ptr = p; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh 2025-10-13 07:49:24.000000000 +0000 @@ -34,135 +34,106 @@ #line 36 "hb-buffer-deserialize-text-unicode.hh" static const unsigned char _deserialize_text_unicode_trans_keys[] = { - 0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 0 + 0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u, + 85u, 117u, 85u, 117u, 0 }; static const char _deserialize_text_unicode_key_spans[] = { - 0, 109, 60, 55, 10, 116, 116, 116, - 116 + 0, 60, 55, 77, 10, 63, 77, 58, + 33, 33 }; static const short _deserialize_text_unicode_index_offsets[] = { - 0, 0, 110, 171, 227, 238, 355, 472, - 589 + 0, 0, 61, 117, 195, 206, 270, 348, + 407, 441 }; static const char _deserialize_text_unicode_indicies[] = { - 0, 0, 0, 0, 0, 1, 1, + 0, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 1, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 4, 5, 1, 1, 3, + 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, + 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5, 1, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 1, 3, - 1, 1, 1, 1, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 1, 1, - 1, 1, 1, 1, 1, 4, 4, 4, - 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 4, 4, 4, - 4, 4, 4, 1, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 1, 1, - 1, 1, 1, 1, 1, 4, 4, 4, - 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 4, 4, 4, - 4, 4, 4, 1, 5, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 1, 7, - 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 8, 1, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 1, 1, 1, 9, 1, 1, 1, 8, - 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 8, - 8, 8, 8, 8, 8, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 10, 1, 11, 11, 11, 11, - 11, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 11, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, - 1, 12, 12, 12, 12, 12, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 13, 1, 12, 12, - 12, 12, 12, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 12, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 11, 1, + 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 11, 1, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 13, 1, 0 + 1, 1, 12, 1, 0 }; static const char _deserialize_text_unicode_trans_targs[] = { - 1, 0, 2, 3, 5, 7, 8, 6, - 5, 4, 1, 6, 6, 1, 8 + 2, 0, 3, 3, 4, 9, 5, 6, + 9, 6, 8, 1, 1 }; static const char _deserialize_text_unicode_trans_actions[] = { - 0, 0, 1, 0, 2, 2, 2, 3, - 0, 4, 3, 0, 5, 5, 0 + 0, 0, 1, 0, 2, 2, 1, 1, + 3, 0, 0, 4, 6 }; static const char _deserialize_text_unicode_eof_actions[] = { - 0, 0, 0, 0, 0, 3, 0, 5, - 5 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5 }; -static const int deserialize_text_unicode_start = 1; -static const int deserialize_text_unicode_first_final = 5; +static const int deserialize_text_unicode_start = 7; +static const int deserialize_text_unicode_first_final = 7; static const int deserialize_text_unicode_error = 0; -static const int deserialize_text_unicode_en_main = 1; +static const int deserialize_text_unicode_en_main = 7; -#line 79 "hb-buffer-deserialize-text-unicode.rl" +#line 80 "hb-buffer-deserialize-text-unicode.rl" static hb_bool_t @@ -172,37 +143,19 @@ const char **end_ptr, hb_font_t *font) { - const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe; - - while (p < pe && ISSPACE (*p)) - p++; - if (p < pe && *p == (buffer->len ? '|' : '<')) - *end_ptr = ++p; - - const char *end = strchr ((char *) p, '>'); - if (end) - pe = eof = end; - else - { - end = strrchr ((char *) p, '|'); - if (end) - pe = eof = end; - else - pe = eof = p; - } - + const char *p = buf, *pe = buf + buf_len, *eof = pe; const char *tok = nullptr; int cs; hb_glyph_info_t info = {0}; const hb_glyph_position_t pos = {0}; -#line 201 "hb-buffer-deserialize-text-unicode.hh" +#line 154 "hb-buffer-deserialize-text-unicode.hh" { cs = deserialize_text_unicode_start; } -#line 206 "hb-buffer-deserialize-text-unicode.hh" +#line 159 "hb-buffer-deserialize-text-unicode.hh" { int _slen; int _trans; @@ -227,38 +180,27 @@ goto _again; switch ( _deserialize_text_unicode_trans_actions[_trans] ) { - case 1: + case 4: #line 38 "hb-buffer-deserialize-text-unicode.rl" { hb_memset (&info, 0, sizeof (info)); } break; - case 2: + case 1: #line 51 "hb-buffer-deserialize-text-unicode.rl" { tok = p; } break; - case 4: + case 2: #line 55 "hb-buffer-deserialize-text-unicode.rl" {if (!parse_hex (tok, p, &info.codepoint )) return false; } break; case 3: -#line 55 "hb-buffer-deserialize-text-unicode.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } -#line 42 "hb-buffer-deserialize-text-unicode.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - if (buffer->have_positions) - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 5: #line 57 "hb-buffer-deserialize-text-unicode.rl" { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 6: #line 42 "hb-buffer-deserialize-text-unicode.rl" { buffer->add_info (info); @@ -268,8 +210,12 @@ buffer->pos[buffer->len - 1] = pos; *end_ptr = p; } +#line 38 "hb-buffer-deserialize-text-unicode.rl" + { + hb_memset (&info, 0, sizeof (info)); +} break; -#line 273 "hb-buffer-deserialize-text-unicode.hh" +#line 219 "hb-buffer-deserialize-text-unicode.hh" } _again: @@ -281,22 +227,7 @@ if ( p == eof ) { switch ( _deserialize_text_unicode_eof_actions[cs] ) { - case 3: -#line 55 "hb-buffer-deserialize-text-unicode.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } -#line 42 "hb-buffer-deserialize-text-unicode.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - if (buffer->have_positions) - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; case 5: -#line 57 "hb-buffer-deserialize-text-unicode.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } #line 42 "hb-buffer-deserialize-text-unicode.rl" { buffer->add_info (info); @@ -307,22 +238,15 @@ *end_ptr = p; } break; -#line 311 "hb-buffer-deserialize-text-unicode.hh" +#line 242 "hb-buffer-deserialize-text-unicode.hh" } } _out: {} } -#line 115 "hb-buffer-deserialize-text-unicode.rl" - +#line 98 "hb-buffer-deserialize-text-unicode.rl" - if (pe < orig_pe && *pe == '>') - { - pe++; - if (p == pe) - p++; - } *end_ptr = p; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc 2025-10-13 07:49:24.000000000 +0000 @@ -169,11 +169,13 @@ if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) { hb_glyph_extents_t extents; - hb_font_get_glyph_extents(font, info[i].codepoint, &extents); - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d", - extents.x_bearing, extents.y_bearing)); - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d", - extents.width, extents.height)); + if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents)) + { + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d", + extents.x_bearing, extents.y_bearing)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d", + extents.width, extents.height)); + } } *p++ = '}'; @@ -318,8 +320,8 @@ if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) { hb_glyph_extents_t extents; - hb_font_get_glyph_extents(font, info[i].codepoint, &extents); - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height)); + if (hb_font_get_glyph_extents(font, info[i].codepoint, &extents)) + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height)); } if (i == end-1) { @@ -737,8 +739,7 @@ * Deserializes glyphs @buffer from textual representation in the format * produced by hb_buffer_serialize_glyphs(). * - * Return value: `true` if parse was successful, `false` if an error - * occurred. + * Return value: `true` if the full string was parsed, `false` otherwise. * * Since: 0.9.7 **/ @@ -810,8 +811,7 @@ * Deserializes Unicode @buffer from textual representation in the format * produced by hb_buffer_serialize_unicode(). * - * Return value: `true` if parse was successful, `false` if an error - * occurred. + * Return value: `true` if the full string was parsed, `false` otherwise. * * Since: 2.7.3 **/ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc 2025-10-13 07:49:24.000000000 +0000 @@ -63,23 +63,24 @@ buffer_verify_monotone (hb_buffer_t *buffer, hb_font_t *font) { - /* Check that clusters are monotone. */ - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES || - buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level)) { - bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + /* Cannot perform this check without monotone clusters. */ + return true; + } - unsigned int num_glyphs; - hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); - for (unsigned int i = 1; i < num_glyphs; i++) - if (info[i-1].cluster != info[i].cluster && - (info[i-1].cluster < info[i].cluster) != is_forward) - { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone."); - return false; - } - } + unsigned int num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + for (unsigned int i = 1; i < num_glyphs; i++) + if (info[i-1].cluster != info[i].cluster && + (info[i-1].cluster < info[i].cluster) != is_forward) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone."); + return false; + } return true; } @@ -92,8 +93,7 @@ unsigned int num_features, const char * const *shapers) { - if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES && - buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level)) { /* Cannot perform this check without monotone clusters. */ return true; @@ -207,8 +207,7 @@ unsigned int num_features, const char * const *shapers) { - if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES && - buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (buffer->cluster_level)) { /* Cannot perform this check without monotone clusters. */ return true; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc 2025-10-13 07:49:24.000000000 +0000 @@ -370,6 +370,18 @@ len++; } +void +hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info, + const hb_glyph_position_t &glyph_pos) +{ + if (unlikely (!ensure (len + 1))) return; + + info[len] = glyph_info; + assert (have_positions); + pos[len] = glyph_pos; + + len++; +} void @@ -518,7 +530,7 @@ hb_buffer_t::merge_clusters_impl (unsigned int start, unsigned int end) { - if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) + if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level)) { unsafe_to_break (start, end); return; @@ -551,7 +563,7 @@ hb_buffer_t::merge_out_clusters (unsigned int start, unsigned int end) { - if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) + if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level)) return; if (unlikely (end - start < 2)) diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.h 2025-10-13 07:49:24.000000000 +0000 @@ -422,6 +422,7 @@ * @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values. * @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level, * equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES. + * @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES: Only group clusters, but don't enforce monotone order. * * Data type for holding HarfBuzz's clustering behavior options. The cluster level * dictates one aspect of how HarfBuzz will treat non-base characters @@ -429,11 +430,26 @@ * * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base * characters are merged into the cluster of the base character that precedes them. + * There is also cluster merging every time the clusters will otherwise become non-monotone. * * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS, non-base characters are initially * assigned their own cluster values, which are not merged into preceding base * clusters. This allows HarfBuzz to perform additional operations like reorder - * sequences of adjacent marks. + * sequences of adjacent marks. The output is still monotone, but the cluster + * values are more granular. + * + * In @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS, non-base characters are assigned their + * own cluster values, which are not merged into preceding base clusters. Moreover, + * the cluster values are not merged into monotone order. This is the most granular + * cluster level, and it is useful for clients that need to know the exact cluster + * values of each character, but is harder to use for clients, since clusters + * might appear in any order. + * + * In @HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES, non-base characters are merged into the + * cluster of the base character that precedes them. This is similar to the Unicode + * Grapheme Cluster algorithm, but it is not exactly the same. The output is + * not forced to be monotone. This is useful for clients that want to use HarfBuzz + * as a cheap implementation of the Unicode Grapheme Cluster algorithm. * * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES is the default, because it maintains * backward compatibility with older versions of HarfBuzz. New client programs that @@ -446,9 +462,52 @@ HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1, HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2, + HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES = 3, HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES } hb_buffer_cluster_level_t; +/** + * HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE: + * @level: #hb_buffer_cluster_level_t to test + * + * Tests whether a cluster level groups cluster values into monotone order. + * Requires that the level be valid. + * + * Since: 11.0.0 + */ +#define HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE(level) \ + ((bool) ((1u << (unsigned) (level)) & \ + ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \ + (1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)))) + +/** + * HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES: + * @level: #hb_buffer_cluster_level_t to test + * + * Tests whether a cluster level groups cluster values by graphemes. Requires + * that the level be valid. + * + * Since: 11.0.0 + */ +#define HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES(level) \ + ((bool) ((1u << (unsigned) (level)) & \ + ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) | \ + (1u << HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES)))) + +/** + * HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS + * @level: #hb_buffer_cluster_level_t to test + * + * Tests whether a cluster level does not group cluster values by graphemes. + * Requires that the level be valid. + * + * Since: 11.0.0 + */ +#define HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS(level) \ + ((bool) ((1u << (unsigned) (level)) & \ + ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARCATERS) | \ + (1u << HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)))) + HB_EXTERN void hb_buffer_set_cluster_level (hb_buffer_t *buffer, hb_buffer_cluster_level_t cluster_level); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh 2025-10-13 07:49:24.000000000 +0000 @@ -229,6 +229,8 @@ HB_INTERNAL void add (hb_codepoint_t codepoint, unsigned int cluster); HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info); + HB_INTERNAL void add_info_and_pos (const hb_glyph_info_t &glyph_info, + const hb_glyph_position_t &glyph_pos); void reverse_range (unsigned start, unsigned end) { @@ -410,6 +412,9 @@ { end = hb_min (end, len); + if (unlikely (end - start > 255)) + return; + if (interior && !from_out_buffer && end - start < 2) return; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-cache.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-cache.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-cache.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-cache.hh 2025-10-13 07:49:24.000000000 +0000 @@ -30,18 +30,31 @@ #include "hb.hh" -/* Implements a lockfree cache for int->int functions. +/* Implements a lockfree and thread-safe cache for int->int functions, + * using (optionally) _relaxed_ atomic integer operations. * - * The cache is a fixed-size array of 16-bit or 32-bit integers. - * The key is split into two parts: the cache index and the rest. + * The cache is a fixed-size array of 16-bit or 32-bit integers, + * typically 256 elements. * - * The cache index is used to index into the array. The rest is used - * to store the key and the value. + * The key is split into two parts: the cache index (high bits) + * and the rest (low bits). + * + * The cache index is used to index into the array. The array + * member is a 16-bit or 32-bit integer that is used *both* + * to store the low bits of the key, and the value. * * The value is stored in the least significant bits of the integer. - * The key is stored in the most significant bits of the integer. - * The key is shifted by cache_bits to the left to make room for the - * value. + * The low bits of the key are stored in the most significant bits + * of the integer. + * + * A cache hit is detected by comparing the low bits of the key + * with the high bits of the integer at the array position indexed + * by the high bits of the key. If they match, the value is extracted + * from the least significant bits of the integer and returned. + * Otherwise, a cache miss is reported. + * + * Cache operations (storage and retrieval) involve just a few + * arithmetic operations and a single memory access. */ template ::type, + hb_atomic_t, + hb_atomic_t>::type, typename std::conditional::type + unsigned short, + unsigned int>::type >::type; static_assert ((key_bits >= cache_bits), ""); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh 2025-10-13 07:49:24.000000000 +0000 @@ -71,7 +71,8 @@ template cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, const int *coords_=nullptr, unsigned int num_coords_=0) - : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) + : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs), + cached_scalars_vector (&acc.cached_scalars_vector) { coords = coords_; num_coords = num_coords_; @@ -80,9 +81,39 @@ set_ivs (acc.privateDicts[fd].ivs); } - void fini () + ~cff2_cs_interp_env_t () { - SUPER::fini (); + release_scalars_vector (scalars); + } + + hb_vector_t *acquire_scalars_vector () const + { + hb_vector_t *scalars = cached_scalars_vector->get_acquire (); + + if (!scalars || !cached_scalars_vector->cmpexch (scalars, nullptr)) + { + scalars = (hb_vector_t *) hb_calloc (1, sizeof (hb_vector_t)); + if (unlikely (!scalars)) + return nullptr; + scalars->init (); + } + + return scalars; + } + + void release_scalars_vector (hb_vector_t *scalars) const + { + if (!scalars) + return; + + scalars->clear (); + + if (!cached_scalars_vector->cmpexch (nullptr, scalars)) + { + scalars->fini (); + hb_free (scalars); + } + scalars = nullptr; } op_code_t fetch_op () @@ -111,14 +142,20 @@ { if (!seen_blend) { - region_count = varStore->varStore.get_region_index_count (get_ivs ()); - if (do_blend) + scalars = acquire_scalars_vector (); + if (unlikely (!scalars)) + SUPER::set_error (); + else { - if (unlikely (!scalars.resize_exact (region_count))) - SUPER::set_error (); - else - varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, - &scalars[0], region_count); + region_count = varStore->varStore.get_region_index_count (get_ivs ()); + if (do_blend) + { + if (unlikely (!scalars->resize_exact (region_count))) + SUPER::set_error (); + else + varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, + &(*scalars)[0], region_count); + } } seen_blend = true; } @@ -149,11 +186,11 @@ double v = 0; if (do_blend) { - if (likely (scalars.length == deltas.length)) + if (likely (scalars && scalars->length == deltas.length)) { - unsigned count = scalars.length; + unsigned count = scalars->length; for (unsigned i = 0; i < count; i++) - v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real (); + v += (double) scalars->arrayZ[i] * deltas.arrayZ[i].to_real (); } } return v; @@ -167,7 +204,8 @@ const CFF2ItemVariationStore *varStore; unsigned int region_count; unsigned int ivs; - hb_vector_t scalars; + hb_vector_t *scalars = nullptr; + hb_atomic_t *> *cached_scalars_vector = nullptr; bool do_blend; bool seen_vsindex_ = false; bool seen_blend = false; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-common.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-common.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-common.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-common.cc 2025-10-13 07:49:24.000000000 +0000 @@ -42,7 +42,7 @@ /* hb_options_t */ -hb_atomic_int_t _hb_options; +hb_atomic_t _hb_options; void _hb_options_init () @@ -273,7 +273,7 @@ /* Thread-safe lockfree language list */ -static hb_atomic_ptr_t langs; +static hb_atomic_t langs; static inline void free_langs () @@ -403,7 +403,7 @@ hb_language_t hb_language_get_default () { - static hb_atomic_ptr_t default_language; + static hb_atomic_t default_language; hb_language_t language = default_language; if (unlikely (language == HB_LANGUAGE_INVALID)) @@ -968,6 +968,9 @@ * understood by hb_feature_from_string(). The client in responsible for * allocating big enough size for @buf, 128 bytes is more than enough. * + * Note that the feature value will be omitted if it is '1', but the + * string won't include any whitespace. + * * Since: 0.9.5 **/ void @@ -1121,6 +1124,8 @@ * understood by hb_variation_from_string(). The client in responsible for * allocating big enough size for @buf, 128 bytes is more than enough. * + * Note that the string won't include any whitespace. + * * Since: 1.4.2 */ void @@ -1212,6 +1217,58 @@ return hb_color_get_blue (color); } +/** + * hb_malloc: + * @size: The size of the memory to allocate. + * + * Allocates @size bytes of memory, using the allocator set at + * compile-time. Typically just malloc(). + * + * Return value: A pointer to the allocated memory. + * + * Since: 11.0.0 + **/ +void* hb_malloc(size_t size) { return hb_malloc_impl (size); } + +/** + * hb_calloc: + * @nmemb: The number of elements to allocate. + * @size: The size of each element. + * + * Allocates @nmemb elements of @size bytes each, initialized to zero, + * using the allocator set at compile-time. Typically just calloc(). + * + * Return value: A pointer to the allocated memory. + * + * Since: 11.0.0 + **/ +void* hb_calloc(size_t nmemb, size_t size) { return hb_calloc_impl (nmemb, size); } + +/** + * hb_realloc: + * @ptr: The pointer to the memory to reallocate. + * @size: The new size of the memory. + * + * Reallocates the memory pointed to by @ptr to @size bytes, using the + * allocator set at compile-time. Typically just realloc(). + * + * Return value: A pointer to the reallocated memory. + * + * Since: 11.0.0 + **/ +void* hb_realloc(void *ptr, size_t size) { return hb_realloc_impl (ptr, size); } + +/** + * hb_free: + * @ptr: The pointer to the memory to free. + * + * Frees the memory pointed to by @ptr, using the allocator set at + * compile-time. Typically just free(). + * + * Since: 11.0.0 + **/ +void hb_free(void *ptr) { hb_free_impl (ptr); } + /* If there is no visibility control, then hb-static.cc will NOT * define anything. Instead, we get it to define one set in here diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-common.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-common.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-common.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-common.h 2025-10-13 07:49:24.000000000 +0000 @@ -65,6 +65,7 @@ #else # include #endif +#include #if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) #define HB_DEPRECATED __attribute__((__deprecated__)) @@ -337,437 +338,7 @@ hb_language_matches (hb_language_t language, hb_language_t specific); -/** - * hb_script_t: - * @HB_SCRIPT_COMMON: `Zyyy` - * @HB_SCRIPT_INHERITED: `Zinh` - * @HB_SCRIPT_UNKNOWN: `Zzzz` - * @HB_SCRIPT_ARABIC: `Arab` - * @HB_SCRIPT_ARMENIAN: `Armn` - * @HB_SCRIPT_BENGALI: `Beng` - * @HB_SCRIPT_CYRILLIC: `Cyrl` - * @HB_SCRIPT_DEVANAGARI: `Deva` - * @HB_SCRIPT_GEORGIAN: `Geor` - * @HB_SCRIPT_GREEK: `Grek` - * @HB_SCRIPT_GUJARATI: `Gujr` - * @HB_SCRIPT_GURMUKHI: `Guru` - * @HB_SCRIPT_HANGUL: `Hang` - * @HB_SCRIPT_HAN: `Hani` - * @HB_SCRIPT_HEBREW: `Hebr` - * @HB_SCRIPT_HIRAGANA: `Hira` - * @HB_SCRIPT_KANNADA: `Knda` - * @HB_SCRIPT_KATAKANA: `Kana` - * @HB_SCRIPT_LAO: `Laoo` - * @HB_SCRIPT_LATIN: `Latn` - * @HB_SCRIPT_MALAYALAM: `Mlym` - * @HB_SCRIPT_ORIYA: `Orya` - * @HB_SCRIPT_TAMIL: `Taml` - * @HB_SCRIPT_TELUGU: `Telu` - * @HB_SCRIPT_THAI: `Thai` - * @HB_SCRIPT_TIBETAN: `Tibt` - * @HB_SCRIPT_BOPOMOFO: `Bopo` - * @HB_SCRIPT_BRAILLE: `Brai` - * @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans` - * @HB_SCRIPT_CHEROKEE: `Cher` - * @HB_SCRIPT_ETHIOPIC: `Ethi` - * @HB_SCRIPT_KHMER: `Khmr` - * @HB_SCRIPT_MONGOLIAN: `Mong` - * @HB_SCRIPT_MYANMAR: `Mymr` - * @HB_SCRIPT_OGHAM: `Ogam` - * @HB_SCRIPT_RUNIC: `Runr` - * @HB_SCRIPT_SINHALA: `Sinh` - * @HB_SCRIPT_SYRIAC: `Syrc` - * @HB_SCRIPT_THAANA: `Thaa` - * @HB_SCRIPT_YI: `Yiii` - * @HB_SCRIPT_DESERET: `Dsrt` - * @HB_SCRIPT_GOTHIC: `Goth` - * @HB_SCRIPT_OLD_ITALIC: `Ital` - * @HB_SCRIPT_BUHID: `Buhd` - * @HB_SCRIPT_HANUNOO: `Hano` - * @HB_SCRIPT_TAGALOG: `Tglg` - * @HB_SCRIPT_TAGBANWA: `Tagb` - * @HB_SCRIPT_CYPRIOT: `Cprt` - * @HB_SCRIPT_LIMBU: `Limb` - * @HB_SCRIPT_LINEAR_B: `Linb` - * @HB_SCRIPT_OSMANYA: `Osma` - * @HB_SCRIPT_SHAVIAN: `Shaw` - * @HB_SCRIPT_TAI_LE: `Tale` - * @HB_SCRIPT_UGARITIC: `Ugar` - * @HB_SCRIPT_BUGINESE: `Bugi` - * @HB_SCRIPT_COPTIC: `Copt` - * @HB_SCRIPT_GLAGOLITIC: `Glag` - * @HB_SCRIPT_KHAROSHTHI: `Khar` - * @HB_SCRIPT_NEW_TAI_LUE: `Talu` - * @HB_SCRIPT_OLD_PERSIAN: `Xpeo` - * @HB_SCRIPT_SYLOTI_NAGRI: `Sylo` - * @HB_SCRIPT_TIFINAGH: `Tfng` - * @HB_SCRIPT_BALINESE: `Bali` - * @HB_SCRIPT_CUNEIFORM: `Xsux` - * @HB_SCRIPT_NKO: `Nkoo` - * @HB_SCRIPT_PHAGS_PA: `Phag` - * @HB_SCRIPT_PHOENICIAN: `Phnx` - * @HB_SCRIPT_CARIAN: `Cari` - * @HB_SCRIPT_CHAM: `Cham` - * @HB_SCRIPT_KAYAH_LI: `Kali` - * @HB_SCRIPT_LEPCHA: `Lepc` - * @HB_SCRIPT_LYCIAN: `Lyci` - * @HB_SCRIPT_LYDIAN: `Lydi` - * @HB_SCRIPT_OL_CHIKI: `Olck` - * @HB_SCRIPT_REJANG: `Rjng` - * @HB_SCRIPT_SAURASHTRA: `Saur` - * @HB_SCRIPT_SUNDANESE: `Sund` - * @HB_SCRIPT_VAI: `Vaii` - * @HB_SCRIPT_AVESTAN: `Avst` - * @HB_SCRIPT_BAMUM: `Bamu` - * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp` - * @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi` - * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli` - * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti` - * @HB_SCRIPT_JAVANESE: `Java` - * @HB_SCRIPT_KAITHI: `Kthi` - * @HB_SCRIPT_LISU: `Lisu` - * @HB_SCRIPT_MEETEI_MAYEK: `Mtei` - * @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb` - * @HB_SCRIPT_OLD_TURKIC: `Orkh` - * @HB_SCRIPT_SAMARITAN: `Samr` - * @HB_SCRIPT_TAI_THAM: `Lana` - * @HB_SCRIPT_TAI_VIET: `Tavt` - * @HB_SCRIPT_BATAK: `Batk` - * @HB_SCRIPT_BRAHMI: `Brah` - * @HB_SCRIPT_MANDAIC: `Mand` - * @HB_SCRIPT_CHAKMA: `Cakm` - * @HB_SCRIPT_MEROITIC_CURSIVE: `Merc` - * @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero` - * @HB_SCRIPT_MIAO: `Plrd` - * @HB_SCRIPT_SHARADA: `Shrd` - * @HB_SCRIPT_SORA_SOMPENG: `Sora` - * @HB_SCRIPT_TAKRI: `Takr` - * @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30 - * @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30 - * @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30 - * @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30 - * @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30 - * @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30 - * @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30 - * @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30 - * @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30 - * @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30 - * @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30 - * @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30 - * @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30 - * @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30 - * @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30 - * @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30 - * @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30 - * @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30 - * @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30 - * @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30 - * @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30 - * @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30 - * @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30 - * @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30 - * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30 - * @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30 - * @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30 - * @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30 - * @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30 - * @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0 - * @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0 - * @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0 - * @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0 - * @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0 - * @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0 - * @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0 - * @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0 - * @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0 - * @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0 - * @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0 - * @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0 - * @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0 - * @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0 - * @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0 - * @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0 - * @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0 - * @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0 - * @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0 - * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0 - * @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0 - * @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7 - * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7 - * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7 - * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7 - * @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0 - * @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0 - * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0 - * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0 - * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0 - * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0 - * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0 - * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0 - * @HB_SCRIPT_GARAY: `Gara`, Since: 10.0.0 - * @HB_SCRIPT_GURUNG_KHEMA: `Gukh`, Since: 10.0.0 - * @HB_SCRIPT_KIRAT_RAI: `Krai`, Since: 10.0.0 - * @HB_SCRIPT_OL_ONAL: `Onao`, Since: 10.0.0 - * @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0 - * @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0 - * @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0 - * @HB_SCRIPT_INVALID: No script set - * - * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding - * to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/). - * - * See also the Script (sc) property of the Unicode Character Database. - * - **/ - -/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */ -typedef enum -{ - HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/ - HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/ - HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/ - - HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/ - HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/ - HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/ - HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/ - HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/ - HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/ - HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/ - HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/ - HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/ - HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/ - HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/ - HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/ - HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/ - HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/ - HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/ - HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/ - HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/ - HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/ - HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/ - HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/ - HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/ - HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/ - - HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/ - - HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/ - HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/ - HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/ - HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/ - HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/ - HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/ - HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/ - HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/ - HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/ - HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/ - HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/ - HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/ - HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/ - HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/ - - HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/ - HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/ - HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/ - - HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/ - HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/ - HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/ - HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/ - - HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/ - HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/ - HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/ - HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/ - HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/ - HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/ - HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/ - - HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/ - HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/ - HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/ - HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/ - HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/ - HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/ - HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/ - HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/ - - HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/ - HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/ - HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/ - HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/ - HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/ - - HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/ - HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/ - HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/ - HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/ - HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/ - HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/ - HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/ - HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/ - HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/ - HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/ - HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/ - - HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/ - HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/ - HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/ - HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/ - HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/ - HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/ - HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/ - HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/ - HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/ - HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/ - HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/ - HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/ - HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/ - HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/ - HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/ - - HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/ - HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/ - HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/ - - HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/ - HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/ - HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/ - HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/ - HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/ - HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/ - HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/ - - /* - * Since: 0.9.30 - */ - HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/ - HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/ - HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/ - HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/ - HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/ - HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/ - HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/ - HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/ - HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/ - HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/ - HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/ - HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/ - HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/ - HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/ - HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/ - HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/ - HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/ - HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/ - HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/ - HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/ - HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/ - HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/ - HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/ - - HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/ - HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/ - HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/ - HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/ - HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/ - HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/ - - /* - * Since 1.3.0 - */ - HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/ - HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/ - HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/ - HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/ - HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/ - HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/ - - /* - * Since 1.6.0 - */ - HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/ - HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/ - HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/ - HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/ - - /* - * Since 1.8.0 - */ - HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/ - HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/ - HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/ - HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/ - HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/ - HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/ - HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/ - - /* - * Since 2.4.0 - */ - HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/ - HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/ - HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/ - HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/ - - /* - * Since 2.6.7 - */ - HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/ - HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/ - HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/ - HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/ - - /* - * Since 3.0.0 - */ - HB_SCRIPT_CYPRO_MINOAN = HB_TAG ('C','p','m','n'), /*14.0*/ - HB_SCRIPT_OLD_UYGHUR = HB_TAG ('O','u','g','r'), /*14.0*/ - HB_SCRIPT_TANGSA = HB_TAG ('T','n','s','a'), /*14.0*/ - HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/ - HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/ - - /* - * Since 3.4.0 - */ - HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'), - - /* - * Since 5.2.0 - */ - HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/ - HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/ - - /* - * Since 10.0.0 - */ - HB_SCRIPT_GARAY = HB_TAG ('G','a','r','a'), /*16.0*/ - HB_SCRIPT_GURUNG_KHEMA = HB_TAG ('G','u','k','h'), /*16.0*/ - HB_SCRIPT_KIRAT_RAI = HB_TAG ('K','r','a','i'), /*16.0*/ - HB_SCRIPT_OL_ONAL = HB_TAG ('O','n','a','o'), /*16.0*/ - HB_SCRIPT_SUNUWAR = HB_TAG ('S','u','n','u'), /*16.0*/ - HB_SCRIPT_TODHRI = HB_TAG ('T','o','d','r'), /*16.0*/ - HB_SCRIPT_TULU_TIGALARI = HB_TAG ('T','u','t','g'), /*16.0*/ - - /* No script set. */ - HB_SCRIPT_INVALID = HB_TAG_NONE, - - /*< private >*/ - - /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t - * without risking undefined behavior. We have two, for historical reasons. - * HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed - * to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well. - * - * See this thread for technicalities: - * - * https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html - */ - _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/ - _HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/ - -} hb_script_t; - +#include "hb-script-list.h" /* Script functions */ @@ -948,6 +519,16 @@ */ typedef struct hb_font_t hb_font_t; +/* Not of much use to clients. */ +HB_EXTERN void* +hb_malloc (size_t size); +HB_EXTERN void* +hb_calloc (size_t nmemb, size_t size); +HB_EXTERN void* +hb_realloc (void *ptr, size_t size); +HB_EXTERN void +hb_free (void *ptr); + HB_END_DECLS #endif /* HB_COMMON_H */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-config.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-config.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-config.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-config.hh 2025-10-13 07:49:24.000000000 +0000 @@ -146,6 +146,7 @@ #ifdef HB_NO_DRAW #define HB_NO_OUTLINE +#define HB_NO_PAINT #endif #ifdef HB_NO_GETENV @@ -191,7 +192,6 @@ #ifdef HB_MINIMIZE_MEMORY_USAGE #define HB_NO_GDEF_CACHE #define HB_NO_OT_LAYOUT_LOOKUP_CACHE -#define HB_NO_OT_FONT_ADVANCE_CACHE #define HB_NO_OT_FONT_CMAP_CACHE #endif diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-debug.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-debug.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-debug.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-debug.hh 2025-10-13 07:49:24.000000000 +0000 @@ -49,15 +49,15 @@ }; union hb_options_union_t { - int i; + unsigned i; hb_options_t opts; }; -static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), ""); +static_assert ((sizeof (hb_atomic_t) >= sizeof (hb_options_union_t)), ""); HB_INTERNAL void _hb_options_init (); -extern HB_INTERNAL hb_atomic_int_t _hb_options; +extern HB_INTERNAL hb_atomic_t _hb_options; static inline hb_options_t hb_options () diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h 2025-10-13 07:49:24.000000000 +0000 @@ -276,6 +276,48 @@ void *user_data); /** + * hb_font_draw_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @draw_funcs: The draw functions to send the shape data to + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 7.0.0 + * XDeprecated: REPLACEME: Use hb_font_draw_glyph_func_or_fail_t instead. + **/ +typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); + +/** + * hb_font_paint_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @paint_funcs: The paint functions to use + * @paint_data: The data accompanying the paint functions + * @palette_index: The color palette to use + * @foreground: The foreground color + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 7.0.0 + * XDeprecated: REPLACEME: Use hb_font_paint_glyph_or_fail_func_t instead. + */ +typedef hb_bool_t (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data); + +/** * hb_font_funcs_set_glyph_shape_func: * @ffuncs: A font-function structure * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign @@ -288,13 +330,49 @@ * Since: 4.0.0 * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead **/ -HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_func) +HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_or_fail_func) HB_EXTERN void hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_shape_func_t func, void *user_data, hb_destroy_func_t destroy); -HB_DEPRECATED_FOR (hb_font_draw_glyph) +/** + * hb_font_funcs_set_draw_glyph_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_draw_glyph_func_t. + * + * Since: 7.0.0 + * XDeprecated: REPLACEME: Use hb_font_funcs_set_draw_glyph_or_fail_func instead. + **/ +HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_or_fail_func) +HB_EXTERN void +hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_draw_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_paint_glyph_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is no longer needed + * + * Sets the implementation function for #hb_font_paint_glyph_func_t. + * + * Since: 7.0.0 + * XDeprecated: REPLACEME: Use hb_font_funcs_set_paint_glyph_or_fail_func() instead. + */ +HB_DEPRECATED_FOR (hb_font_funcs_set_paint_glyph_or_fail_func) +HB_EXTERN void +hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_paint_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); + +HB_DEPRECATED_FOR (hb_font_draw_glyph_or_fail) HB_EXTERN void hb_font_get_glyph_shape (hb_font_t *font, hb_codepoint_t glyph, diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-draw.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-draw.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.cc 2025-10-13 07:49:24.000000000 +0000 @@ -28,6 +28,11 @@ #include "hb-draw.hh" +#include "hb-geometry.hh" + +#include "hb-machinery.hh" + + /** * SECTION:hb-draw * @title: hb-draw @@ -455,4 +460,92 @@ } +static void +hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_extents_t *extents = (hb_extents_t *) data; + + extents->add_point (to_x, to_y); +} + +static void +hb_draw_extents_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_extents_t *extents = (hb_extents_t *) data; + + extents->add_point (to_x, to_y); +} + +static void +hb_draw_extents_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_extents_t *extents = (hb_extents_t *) data; + + extents->add_point (control_x, control_y); + extents->add_point (to_x, to_y); +} + +static void +hb_draw_extents_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_extents_t *extents = (hb_extents_t *) data; + + extents->add_point (control1_x, control1_y); + extents->add_point (control2_x, control2_y); + extents->add_point (to_x, to_y); +} + +static inline void free_static_draw_extents_funcs (); + +static struct hb_draw_extents_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t +{ + static hb_draw_funcs_t *create () + { + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + + hb_draw_funcs_set_move_to_func (funcs, hb_draw_extents_move_to, nullptr, nullptr); + hb_draw_funcs_set_line_to_func (funcs, hb_draw_extents_line_to, nullptr, nullptr); + hb_draw_funcs_set_quadratic_to_func (funcs, hb_draw_extents_quadratic_to, nullptr, nullptr); + hb_draw_funcs_set_cubic_to_func (funcs, hb_draw_extents_cubic_to, nullptr, nullptr); + + hb_draw_funcs_make_immutable (funcs); + + hb_atexit (free_static_draw_extents_funcs); + + return funcs; + } +} static_draw_extents_funcs; + +static inline +void free_static_draw_extents_funcs () +{ + static_draw_extents_funcs.free_instance (); +} + +hb_draw_funcs_t * +hb_draw_extents_get_funcs () +{ + return static_draw_extents_funcs.get_unconst (); +} + + #endif diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-draw.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-draw.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.h 2025-10-13 07:49:24.000000000 +0000 @@ -70,7 +70,7 @@ * * The default #hb_draw_state_t at the start of glyph drawing. */ -#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}, {0.}} +#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0}, {0}, {0}, {0}, {0}, {0}, {0}} /** diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-draw.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-draw.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-draw.hh 2025-10-13 07:49:24.000000000 +0000 @@ -99,6 +99,7 @@ float to_x, float to_y) { if (unlikely (st.path_open)) close_path (draw_data, st); + st.current_x = to_x; st.current_y = to_y; } @@ -109,7 +110,9 @@ float to_x, float to_y) { if (unlikely (!st.path_open)) start_path (draw_data, st); + emit_line_to (draw_data, st, to_x, to_y); + st.current_x = to_x; st.current_y = to_y; } @@ -121,7 +124,9 @@ float to_x, float to_y) { if (unlikely (!st.path_open)) start_path (draw_data, st); + emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); + st.current_x = to_x; st.current_y = to_y; } @@ -134,7 +139,9 @@ float to_x, float to_y) { if (unlikely (!st.path_open)) start_path (draw_data, st); + emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); + st.current_x = to_x; st.current_y = to_y; } @@ -168,9 +175,8 @@ struct hb_draw_session_t { - hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f) - : slant {slant_}, not_slanted {slant == 0.f}, - funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT + hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_) + : funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT {} ~hb_draw_session_t () { close_path (); } @@ -178,36 +184,23 @@ HB_ALWAYS_INLINE void move_to (float to_x, float to_y) { - if (likely (not_slanted)) - funcs->move_to (draw_data, st, - to_x, to_y); - else - funcs->move_to (draw_data, st, - to_x + to_y * slant, to_y); + funcs->move_to (draw_data, st, + to_x, to_y); } HB_ALWAYS_INLINE void line_to (float to_x, float to_y) { - if (likely (not_slanted)) - funcs->line_to (draw_data, st, - to_x, to_y); - else - funcs->line_to (draw_data, st, - to_x + to_y * slant, to_y); + funcs->line_to (draw_data, st, + to_x, to_y); } void HB_ALWAYS_INLINE quadratic_to (float control_x, float control_y, float to_x, float to_y) { - if (likely (not_slanted)) - funcs->quadratic_to (draw_data, st, - control_x, control_y, - to_x, to_y); - else - funcs->quadratic_to (draw_data, st, - control_x + control_y * slant, control_y, - to_x + to_y * slant, to_y); + funcs->quadratic_to (draw_data, st, + control_x, control_y, + to_x, to_y); } void HB_ALWAYS_INLINE @@ -215,16 +208,10 @@ float control2_x, float control2_y, float to_x, float to_y) { - if (likely (not_slanted)) - funcs->cubic_to (draw_data, st, - control1_x, control1_y, - control2_x, control2_y, - to_x, to_y); - else - funcs->cubic_to (draw_data, st, - control1_x + control1_y * slant, control1_y, - control2_x + control2_y * slant, control2_y, - to_x + to_y * slant, to_y); + funcs->cubic_to (draw_data, st, + control1_x, control1_y, + control2_x, control2_y, + to_x, to_y); } HB_ALWAYS_INLINE void close_path () @@ -233,11 +220,14 @@ } public: - float slant; - bool not_slanted; hb_draw_funcs_t *funcs; void *draw_data; hb_draw_state_t st; }; + +HB_INTERNAL hb_draw_funcs_t * +hb_draw_extents_get_funcs (); + + #endif /* HB_DRAW_HH */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-face.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-face.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.cc 2025-10-13 07:49:24.000000000 +0000 @@ -34,6 +34,16 @@ #include "hb-ot-face.hh" #include "hb-ot-cmap-table.hh" +#ifdef HAVE_FREETYPE +#include "hb-ft.h" +#endif +#ifdef HAVE_CORETEXT +#include "hb-coretext.h" +#endif +#ifdef HAVE_DIRECTWRITE +#include "hb-directwrite.h" +#endif + /** * SECTION:hb-face @@ -72,14 +82,14 @@ if (unlikely (!blob)) return 0; - /* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */ - /* Make API signature const after. */ - hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob (hb_blob_reference (blob)); - const OT::OpenTypeFontFile& ot = *sanitized->as (); - unsigned int ret = ot.get_face_count (); - hb_blob_destroy (sanitized); + hb_sanitize_context_t c (blob); + + const char *start = hb_blob_get_data (blob, nullptr); + auto *ot = reinterpret_cast (const_cast (start)); + if (unlikely (!ot->sanitize (&c))) + return 0; - return ret; + return ot->get_face_count (); } /* @@ -318,7 +328,209 @@ return face; } + +static struct supported_face_loaders_t { + char name[16]; + hb_face_t * (*from_file) (const char *font_file, unsigned face_index); + hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index); +} supported_face_loaders[] = +{ + {"ot", +#ifndef HB_NO_OPEN + hb_face_create_from_file_or_fail, +#else + nullptr, +#endif + hb_face_create_or_fail + }, +#ifdef HAVE_FREETYPE + {"ft", + hb_ft_face_create_from_file_or_fail, + hb_ft_face_create_from_blob_or_fail + }, #endif +#ifdef HAVE_CORETEXT + {"coretext", + hb_coretext_face_create_from_file_or_fail, + hb_coretext_face_create_from_blob_or_fail + }, +#endif +#ifdef HAVE_DIRECTWRITE + {"directwrite", + hb_directwrite_face_create_from_file_or_fail, + hb_directwrite_face_create_from_blob_or_fail + }, +#endif +}; + +static const char *get_default_loader_name () +{ + static hb_atomic_t static_loader_name; + const char *loader_name = static_loader_name.get_acquire (); + if (!loader_name) + { + loader_name = getenv ("HB_FACE_LOADER"); + if (!loader_name) + loader_name = ""; + if (!static_loader_name.cmpexch (nullptr, loader_name)) + loader_name = static_loader_name.get_acquire (); + } + return loader_name; +} + +/** + * hb_face_create_from_file_or_fail_using: + * @file_name: A font filename + * @index: The index of the face within the file + * @loader_name: (nullable): The name of the loader to use, or `NULL` + * + * A thin wrapper around the face loader functions registered with HarfBuzz. + * If @loader_name is `NULL` or the empty string, the first available loader + * is used. + * + * For example, the FreeType ("ft") loader might be able to load + * WOFF and WOFF2 files if FreeType is built with those features, + * whereas the OpenType ("ot") loader will not. + * + * Return value: (transfer full): The new face object, or `NULL` if + * the file cannot be read or the loader fails to load the face. + * + * Since: 11.0.0 + **/ +hb_face_t * +hb_face_create_from_file_or_fail_using (const char *file_name, + unsigned int index, + const char *loader_name) +{ + // Duplicated in hb_face_create_or_fail_using + bool retry = false; + if (!loader_name || !*loader_name) + { + loader_name = get_default_loader_name (); + retry = true; + } + if (loader_name && !*loader_name) loader_name = nullptr; + +retry: + for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) + { + if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name))) + return supported_face_loaders[i].from_file (file_name, index); + } + + if (retry) + { + retry = false; + loader_name = nullptr; + goto retry; + } + + return nullptr; +} + +/** + * hb_face_create_or_fail_using: + * @blob: #hb_blob_t to work upon + * @index: The index of the face within @blob + * @loader_name: (nullable): The name of the loader to use, or `NULL` + * + * A thin wrapper around the face loader functions registered with HarfBuzz. + * If @loader_name is `NULL` or the empty string, the first available loader + * is used. + * + * For example, the FreeType ("ft") loader might be able to load + * WOFF and WOFF2 files if FreeType is built with those features, + * whereas the OpenType ("ot") loader will not. + * + * Return value: (transfer full): The new face object, or `NULL` if + * the loader fails to load the face. + * + * Since: 11.0.0 + **/ +hb_face_t * +hb_face_create_or_fail_using (hb_blob_t *blob, + unsigned int index, + const char *loader_name) +{ + // Duplicated in hb_face_create_from_file_or_fail_using + bool retry = false; + if (!loader_name || !*loader_name) + { + loader_name = get_default_loader_name (); + retry = true; + } + if (loader_name && !*loader_name) loader_name = nullptr; + +retry: + for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) + { + if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name))) + return supported_face_loaders[i].from_blob (blob, index); + } + + if (retry) + { + retry = false; + loader_name = nullptr; + goto retry; + } + + return nullptr; +} + +static inline void free_static_face_loader_list (); + +static const char * const nil_face_loader_list[] = {nullptr}; + +static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t +{ + static const char ** create () + { + const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *)); + if (unlikely (!face_loader_list)) + return nullptr; + + unsigned i; + for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) + face_loader_list[i] = supported_face_loaders[i].name; + face_loader_list[i] = nullptr; + + hb_atexit (free_static_face_loader_list); + + return face_loader_list; + } + static void destroy (const char **l) + { hb_free (l); } + static const char * const * get_null () + { return nil_face_loader_list; } +} static_face_loader_list; + +static inline +void free_static_face_loader_list () +{ + static_face_loader_list.free_instance (); +} + +/** + * hb_face_list_loaders: + * + * Retrieves the list of face loaders supported by HarfBuzz. + * + * Return value: (transfer none) (array zero-terminated=1): a + * `NULL`-terminated array of supported face loaders + * constant strings. The returned array is owned by HarfBuzz + * and should not be modified or freed. + * + * Since: 11.0.0 + **/ +const char ** +hb_face_list_loaders () +{ + return static_face_loader_list.get_unconst (); +} +#endif + /** * hb_face_get_empty: @@ -460,7 +672,7 @@ * Since: 0.9.2 **/ hb_bool_t -hb_face_is_immutable (const hb_face_t *face) +hb_face_is_immutable (hb_face_t *face) { return hb_object_is_immutable (face); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-face.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-face.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.h 2025-10-13 07:49:24.000000000 +0000 @@ -64,9 +64,23 @@ unsigned int index); HB_EXTERN hb_face_t * +hb_face_create_or_fail_using (hb_blob_t *blob, + unsigned int index, + const char *loader_name); + +HB_EXTERN hb_face_t * hb_face_create_from_file_or_fail (const char *file_name, unsigned int index); +HB_EXTERN hb_face_t * +hb_face_create_from_file_or_fail_using (const char *file_name, + unsigned int index, + const char *loader_name); + +HB_EXTERN const char ** +hb_face_list_loaders (void); + + /** * hb_reference_table_func_t: * @face: an #hb_face_t to reference table for @@ -117,7 +131,7 @@ hb_face_make_immutable (hb_face_t *face); HB_EXTERN hb_bool_t -hb_face_is_immutable (const hb_face_t *face); +hb_face_is_immutable (hb_face_t *face); HB_EXTERN hb_blob_t * diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-face.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-face.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-face.hh 2025-10-13 07:49:24.000000000 +0000 @@ -49,8 +49,8 @@ hb_object_header_t header; unsigned int index; /* Face index in a collection, zero-based. */ - mutable hb_atomic_int_t upem; /* Units-per-EM. */ - mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */ + mutable hb_atomic_t upem; /* Units-per-EM. */ + mutable hb_atomic_t num_glyphs;/* Number of glyphs. */ hb_reference_table_func_t reference_table_func; void *user_data; @@ -70,7 +70,7 @@ plan_node_t *next; }; #ifndef HB_NO_SHAPER - hb_atomic_ptr_t shape_plans; + hb_atomic_t shape_plans; #endif hb_blob_t *reference_table (hb_tag_t tag) const diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-font.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-font.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.cc 2025-10-13 07:49:24.000000000 +0000 @@ -38,6 +38,22 @@ #include "hb-ot-var-avar-table.hh" #include "hb-ot-var-fvar-table.hh" +#ifndef HB_NO_OT_FONT +#include "hb-ot.h" +#endif +#ifdef HAVE_FREETYPE +#include "hb-ft.h" +#endif +#ifdef HAVE_FONTATIONS +#include "hb-fontations.h" +#endif +#ifdef HAVE_CORETEXT +#include "hb-coretext.h" +#endif +#ifdef HAVE_DIRECTWRITE +#include "hb-directwrite.h" +#endif + /** * SECTION:hb-font @@ -87,7 +103,7 @@ hb_font_extents_t *extents, void *user_data HB_UNUSED) { - hb_bool_t ret = font->parent->get_font_h_extents (extents); + hb_bool_t ret = font->parent->get_font_h_extents (extents, false); if (ret) { extents->ascender = font->parent_scale_y_distance (extents->ascender); extents->descender = font->parent_scale_y_distance (extents->descender); @@ -112,7 +128,7 @@ hb_font_extents_t *extents, void *user_data HB_UNUSED) { - hb_bool_t ret = font->parent->get_font_v_extents (extents); + hb_bool_t ret = font->parent->get_font_v_extents (extents, false); if (ret) { extents->ascender = font->parent_scale_x_distance (extents->ascender); extents->descender = font->parent_scale_x_distance (extents->descender); @@ -218,10 +234,10 @@ if (font->has_glyph_h_advances_func_set ()) { hb_position_t ret; - font->get_glyph_h_advances (1, &glyph, 0, &ret, 0); + font->get_glyph_h_advances (1, &glyph, 0, &ret, 0, false); return ret; } - return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph)); + return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph, false)); } static hb_position_t @@ -243,10 +259,10 @@ if (font->has_glyph_v_advances_func_set ()) { hb_position_t ret; - font->get_glyph_v_advances (1, &glyph, 0, &ret, 0); + font->get_glyph_v_advances (1, &glyph, 0, &ret, 0, false); return ret; } - return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph)); + return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph, false)); } #define hb_font_get_glyph_h_advances_nil hb_font_get_glyph_h_advances_default @@ -265,7 +281,7 @@ { for (unsigned int i = 0; i < count; i++) { - *first_advance = font->get_glyph_h_advance (*first_glyph); + *first_advance = font->get_glyph_h_advance (*first_glyph, false); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } @@ -274,7 +290,8 @@ font->parent->get_glyph_h_advances (count, first_glyph, glyph_stride, - first_advance, advance_stride); + first_advance, advance_stride, + false); for (unsigned int i = 0; i < count; i++) { *first_advance = font->parent_scale_x_distance (*first_advance); @@ -297,7 +314,7 @@ { for (unsigned int i = 0; i < count; i++) { - *first_advance = font->get_glyph_v_advance (*first_glyph); + *first_advance = font->get_glyph_v_advance (*first_glyph, false); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } @@ -306,7 +323,8 @@ font->parent->get_glyph_v_advances (count, first_glyph, glyph_stride, - first_advance, advance_stride); + first_advance, advance_stride, + false); for (unsigned int i = 0; i < count; i++) { *first_advance = font->parent_scale_y_distance (*first_advance); @@ -426,7 +444,7 @@ hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { - hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents); + hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents, false); if (ret) { font->parent_scale_position (&extents->x_bearing, &extents->y_bearing); font->parent_scale_distance (&extents->width, &extents->height); @@ -456,7 +474,7 @@ hb_position_t *y, void *user_data HB_UNUSED) { - hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y); + hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y, false); if (ret) font->parent_scale_position (x, y); return ret; @@ -508,26 +526,28 @@ return font->parent->get_glyph_from_name (name, len, glyph); } -static void -hb_font_draw_glyph_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, - void *draw_data, - void *user_data HB_UNUSED) +static hb_bool_t +hb_font_draw_glyph_or_fail_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) { + return false; } -static void -hb_font_paint_glyph_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, - hb_paint_funcs_t *paint_funcs HB_UNUSED, - void *paint_data HB_UNUSED, - unsigned int palette HB_UNUSED, - hb_color_t foreground HB_UNUSED, - void *user_data HB_UNUSED) +static hb_bool_t +hb_font_paint_glyph_or_fail_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_paint_funcs_t *paint_funcs HB_UNUSED, + void *paint_data HB_UNUSED, + unsigned int palette HB_UNUSED, + hb_color_t foreground HB_UNUSED, + void *user_data HB_UNUSED) { + return false; } typedef struct hb_font_draw_glyph_default_adaptor_t { @@ -535,7 +555,6 @@ void *draw_data; float x_scale; float y_scale; - float slant; } hb_font_draw_glyph_default_adaptor_t; static void @@ -548,10 +567,9 @@ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; - float slant = adaptor->slant; adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st, - x_scale * to_x + slant * to_y, y_scale * to_y); + x_scale * to_x, y_scale * to_y); } static void @@ -563,13 +581,12 @@ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; - float slant = adaptor->slant; - st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_x = st->current_x * x_scale; st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st, - x_scale * to_x + slant * to_y, y_scale * to_y); + x_scale * to_x, y_scale * to_y); } static void @@ -582,14 +599,13 @@ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; - float slant = adaptor->slant; - st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_x = st->current_x * x_scale; st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st, - x_scale * control_x + slant * control_y, y_scale * control_y, - x_scale * to_x + slant * to_y, y_scale * to_y); + x_scale * control_x, y_scale * control_y, + x_scale * to_x, y_scale * to_y); } static void @@ -603,15 +619,14 @@ hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; - float slant = adaptor->slant; - st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_x = st->current_x * x_scale; st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st, - x_scale * control1_x + slant * control1_y, y_scale * control1_y, - x_scale * control2_x + slant * control2_y, y_scale * control2_y, - x_scale * to_x + slant * to_y, y_scale * to_y); + x_scale * control1_x, y_scale * control1_y, + x_scale * control2_x, y_scale * control2_y, + x_scale * to_x, y_scale * to_y); } static void @@ -634,49 +649,47 @@ } }; -static void -hb_font_draw_glyph_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, - void *draw_data, - void *user_data HB_UNUSED) +static hb_bool_t +hb_font_draw_glyph_or_fail_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) { hb_font_draw_glyph_default_adaptor_t adaptor = { draw_funcs, draw_data, font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f, - font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f, - font->parent->y_scale ? (font->slant - font->parent->slant) * - (float) font->x_scale / (float) font->parent->y_scale : 0.f + font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f }; - font->parent->draw_glyph (glyph, - const_cast (&_hb_draw_funcs_default), - &adaptor); + return font->parent->draw_glyph_or_fail (glyph, + const_cast (&_hb_draw_funcs_default), + &adaptor, + false); } -static void -hb_font_paint_glyph_default (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - hb_paint_funcs_t *paint_funcs, - void *paint_data, - unsigned int palette, - hb_color_t foreground, - void *user_data) +static hb_bool_t +hb_font_paint_glyph_or_fail_default (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, + void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) { paint_funcs->push_transform (paint_data, - font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f, - font->parent->y_scale ? (font->slant - font->parent->slant) * - (float) font->x_scale / (float) font->parent->y_scale : 0.f, - 0.f, - font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f, - 0.f, 0.f); + font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0, 0, + 0, font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0, + 0, 0); - font->parent->paint_glyph (glyph, paint_funcs, paint_data, palette, foreground); + bool ret = font->parent->paint_glyph_or_fail (glyph, paint_funcs, paint_data, palette, foreground); paint_funcs->pop_transform (paint_data); + + return ret; } DEFINE_NULL_INSTANCE (hb_font_funcs_t) = @@ -1414,6 +1427,92 @@ #endif /** + * hb_font_draw_glyph_or_fail: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID + * @dfuncs: #hb_draw_funcs_t to draw to + * @draw_data: User data to pass to draw callbacks + * + * Draws the outline that corresponds to a glyph in the specified @font. + * + * This is a newer name for hb_font_draw_glyph(), that returns `false` + * if the font has no outlines for the glyph. + * + * The outline is returned by way of calls to the callbacks of the @dfuncs + * objects, with @draw_data passed to them. + * + * Return value: `true` if glyph was drawn, `false` otherwise + * + * XSince: REPLACEME + **/ +hb_bool_t +hb_font_draw_glyph_or_fail (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data) +{ + return font->draw_glyph_or_fail (glyph, dfuncs, draw_data); +} + +/** + * hb_font_paint_glyph_or_fail: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID + * @pfuncs: #hb_paint_funcs_t to paint with + * @paint_data: User data to pass to paint callbacks + * @palette_index: The index of the font's color palette to use + * @foreground: The foreground color, unpremultipled + * + * Paints a color glyph. + * + * This function is similar to, but lower-level than, + * hb_font_paint_glyph(). It is suitable for clients that + * need more control. If there are no color glyphs available, + * it will return `false`. The client can then fall back to + * hb_font_draw_glyph_or_fail() for the monochrome outline glyph. + * + * The painting instructions are returned by way of calls to + * the callbacks of the @funcs object, with @paint_data passed + * to them. + * + * If the font has color palettes (see hb_ot_color_has_palettes()), + * then @palette_index selects the palette to use. If the font only + * has one palette, this will be 0. + * + * Return value: `true` if glyph was painted, `false` otherwise + * + * XSince: REPLACEME + */ +hb_bool_t +hb_font_paint_glyph_or_fail (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground) +{ + return font->paint_glyph_or_fail (glyph, pfuncs, paint_data, palette_index, foreground); +} + +/* A bit higher-level, and with fallback */ + +void +hb_font_t::paint_glyph (hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground) +{ + if (paint_glyph_or_fail (glyph, + paint_funcs, paint_data, + palette, foreground)) + return; + + /* Fallback for outline glyph. */ + paint_funcs->push_clip_glyph (paint_data, glyph, this); + paint_funcs->color (paint_data, true, foreground); + paint_funcs->pop_clip (paint_data); +} + + +/** * hb_font_draw_glyph: * @font: #hb_font_t to work upon * @glyph: The glyph ID @@ -1422,6 +1521,9 @@ * * Draws the outline that corresponds to a glyph in the specified @font. * + * This is an older name for hb_font_draw_glyph_or_fail(), with no + * return value. + * * The outline is returned by way of calls to the callbacks of the @dfuncs * objects, with @draw_data passed to them. * @@ -1429,10 +1531,10 @@ **/ void hb_font_draw_glyph (hb_font_t *font, - hb_codepoint_t glyph, - hb_draw_funcs_t *dfuncs, void *draw_data) + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data) { - font->draw_glyph (glyph, dfuncs, draw_data); + (void) hb_font_draw_glyph_or_fail (font, glyph, dfuncs, draw_data); } /** @@ -1444,7 +1546,10 @@ * @palette_index: The index of the font's color palette to use * @foreground: The foreground color, unpremultipled * - * Paints the glyph. + * Paints the glyph. This function is similar to + * hb_font_paint_glyph_or_fail(), but if painting a color glyph + * failed, it will fall back to painting an outline monochrome + * glyph. * * The painting instructions are returned by way of calls to * the callbacks of the @funcs object, with @paint_data passed @@ -1466,8 +1571,6 @@ font->paint_glyph (glyph, pfuncs, paint_data, palette_index, foreground); } -/* A bit higher-level, and with fallback */ - /** * hb_font_get_extents_for_direction: * @font: #hb_font_t to work upon @@ -1854,10 +1957,7 @@ { hb_font_t *font = _hb_font_create (face); -#ifndef HB_NO_OT_FONT - /* Install our in-house, very lightweight, funcs. */ - hb_ot_font_set_funcs (font); -#endif + hb_font_set_funcs_using (font, nullptr); #ifndef HB_NO_VAR if (face && face->index >> 16) @@ -1880,7 +1980,8 @@ font->design_coords = design_coords; font->num_coords = coords_length; - font->mults_changed (); // Easiest to call this to drop cached data + font->changed (); + font->serial_coords = font->serial; } /** @@ -1935,7 +2036,8 @@ } } - font->mults_changed (); + font->changed (); + font->serial_coords = font->serial; return font; } @@ -2023,7 +2125,7 @@ hb_bool_t replace) { if (!hb_object_is_immutable (font)) - font->serial++; + font->changed (); return hb_object_set_user_data (font, key, data, destroy, replace); } @@ -2098,7 +2200,7 @@ unsigned int hb_font_get_serial (hb_font_t *font) { - return font->serial; + return font->serial.get_acquire (); } /** @@ -2117,9 +2219,7 @@ if (hb_object_is_immutable (font)) return; - font->serial++; - - font->mults_changed (); + font->changed (); } /** @@ -2141,8 +2241,6 @@ if (parent == font->parent) return; - font->serial++; - if (!parent) parent = hb_font_get_empty (); @@ -2151,6 +2249,8 @@ font->parent = hb_font_reference (parent); hb_font_destroy (old); + + font->changed (); } /** @@ -2188,8 +2288,6 @@ if (face == font->face) return; - font->serial++; - if (unlikely (!face)) face = hb_face_get_empty (); @@ -2197,9 +2295,12 @@ hb_face_make_immutable (face); font->face = hb_face_reference (face); - font->mults_changed (); + font->changed (); hb_face_destroy (old); + + font->changed (); + font->serial_coords = font->serial; } /** @@ -2244,8 +2345,6 @@ return; } - font->serial++; - if (font->destroy) font->destroy (font->user_data); @@ -2257,6 +2356,8 @@ font->klass = klass; font->user_data = font_data; font->destroy = destroy; + + font->changed (); } /** @@ -2283,15 +2384,151 @@ return; } - font->serial++; - if (font->destroy) font->destroy (font->user_data); font->user_data = font_data; font->destroy = destroy; + + font->changed (); +} + +static struct supported_font_funcs_t { + char name[16]; + void (*func) (hb_font_t *); +} supported_font_funcs[] = +{ +#ifndef HB_NO_OT_FONT + {"ot", hb_ot_font_set_funcs}, +#endif +#ifdef HAVE_FREETYPE + {"ft", hb_ft_font_set_funcs}, +#endif +#ifdef HAVE_FONTATIONS + {"fontations",hb_fontations_font_set_funcs}, +#endif +#ifdef HAVE_CORETEXT + {"coretext", hb_coretext_font_set_funcs}, +#endif +#ifdef HAVE_DIRECTWRITE + {"directwrite",hb_directwrite_font_set_funcs}, +#endif +}; + +static const char *get_default_funcs_name () +{ + static hb_atomic_t static_funcs_name; + const char *name = static_funcs_name.get_acquire (); + if (!name) + { + name = getenv ("HB_FONT_FUNCS"); + if (!name) + name = ""; + if (!static_funcs_name.cmpexch (nullptr, name)) + name = static_funcs_name.get_acquire (); + } + return name; +} + +/** + * hb_font_set_funcs_using: + * @font: #hb_font_t to work upon + * @name: The name of the font-functions structure to use, or `NULL` + * + * Sets the font-functions structure to use for a font, based on the + * specified name. + * + * If @name is `NULL` or the empty string, the default (first) functioning font-functions + * are used. This default can be changed by setting the `HB_FONT_FUNCS` environment + * variable to the name of the desired font-functions. + * + * Return value: `true` if the font-functions was found and set, `false` otherwise + * + * Since: 11.0.0 + **/ +hb_bool_t +hb_font_set_funcs_using (hb_font_t *font, + const char *name) +{ + bool retry = false; + + if (!name || !*name) + { + name = get_default_funcs_name (); + retry = true; + } + if (name && !*name) name = nullptr; + +retry: + for (unsigned i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) + if (!name || strcmp (supported_font_funcs[i].name, name) == 0) + { + supported_font_funcs[i].func (font); + if (name || font->klass != hb_font_funcs_get_empty ()) + return true; + } + + if (retry) + { + retry = false; + name = nullptr; + goto retry; + } + + return false; } +static inline void free_static_font_funcs_list (); + +static const char * const nil_font_funcs_list[] = {nullptr}; + +static struct hb_font_funcs_list_lazy_loader_t : hb_lazy_loader_t +{ + static const char ** create () + { + const char **font_funcs_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_font_funcs), sizeof (const char *)); + if (unlikely (!font_funcs_list)) + return nullptr; + + unsigned i; + for (i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) + font_funcs_list[i] = supported_font_funcs[i].name; + font_funcs_list[i] = nullptr; + + hb_atexit (free_static_font_funcs_list); + + return font_funcs_list; + } + static void destroy (const char **l) + { hb_free (l); } + static const char * const * get_null () + { return nil_font_funcs_list; } +} static_font_funcs_list; + +static inline +void free_static_font_funcs_list () +{ + static_font_funcs_list.free_instance (); +} + +/** + * hb_font_list_funcs: + * + * Retrieves the list of font functions supported by HarfBuzz. + * + * Return value: (transfer none) (array zero-terminated=1): a + * `NULL`-terminated array of supported font functions + * constant strings. The returned array is owned by HarfBuzz + * and should not be modified or freed. + * + * Since: 11.0.0 + **/ +const char ** +hb_font_list_funcs () +{ + return static_font_funcs_list.get_unconst (); +} /** * hb_font_set_scale: @@ -2339,11 +2576,10 @@ if (font->x_scale == x_scale && font->y_scale == y_scale) return; - font->serial++; - font->x_scale = x_scale; font->y_scale = y_scale; - font->mults_changed (); + + font->changed (); } /** @@ -2390,10 +2626,10 @@ if (font->x_ppem == x_ppem && font->y_ppem == y_ppem) return; - font->serial++; - font->x_ppem = x_ppem; font->y_ppem = y_ppem; + + font->changed (); } /** @@ -2437,9 +2673,9 @@ if (font->ptem == ptem) return; - font->serial++; - font->ptem = ptem; + + font->changed (); } /** @@ -2460,6 +2696,23 @@ } /** + * hb_font_is_synthetic: + * @font: #hb_font_t to work upon + * + * Tests whether a font is synthetic. A synthetic font is one + * that has either synthetic slant or synthetic bold set on it. + * + * Return value: `true` if the font is synthetic, `false` otherwise. + * + * XSince: REPLACEME + */ +hb_bool_t +hb_font_is_synthetic (hb_font_t *font) +{ + return font->is_synthetic (); +} + +/** * hb_font_set_synthetic_bold: * @font: #hb_font_t to work upon * @x_embolden: the amount to embolden horizontally @@ -2476,7 +2729,7 @@ * points of the glyph shape. * * Synthetic boldness is applied when rendering a glyph via - * hb_font_draw_glyph(). + * hb_font_draw_glyph_or_fail(). * * If @in_place is `false`, then glyph advance-widths are also * adjusted, otherwise they are not. The in-place mode is @@ -2499,12 +2752,11 @@ font->embolden_in_place == (bool) in_place) return; - font->serial++; - font->x_embolden = x_embolden; font->y_embolden = y_embolden; font->embolden_in_place = in_place; - font->mults_changed (); + + font->changed (); } /** @@ -2541,7 +2793,7 @@ * HarfBuzz needs to know this value to adjust shaping results, * metrics, and style values to match the slanted rendering. * - * Note: The glyph shape fetched via the hb_font_draw_glyph() + * Note: The glyph shape fetched via the hb_font_draw_glyph_or_fail() * function is slanted to reflect this value as well. * * Note: The slant value is a ratio. For example, a @@ -2558,10 +2810,9 @@ if (font->slant == slant) return; - font->serial++; - font->slant = slant; - font->mults_changed (); + + font->changed (); } /** @@ -2607,8 +2858,6 @@ if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; - if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE) { hb_font_set_var_coords_normalized (font, nullptr, 0); @@ -2677,8 +2926,6 @@ if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; - // TODO Share some of this code with set_variations() const OT::fvar &fvar = *font->face->table.fvar; @@ -2749,8 +2996,6 @@ if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; - int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr; float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; @@ -2787,8 +3032,6 @@ if (font->instance_index == instance_index) return; - font->serial_coords = ++font->serial; - font->instance_index = instance_index; hb_font_set_variations (font, nullptr, 0); } @@ -2834,8 +3077,6 @@ if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; - int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr; int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr; float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr; @@ -3058,12 +3299,134 @@ #ifndef HB_DISABLE_DEPRECATED + +struct hb_draw_glyph_closure_t +{ + hb_font_draw_glyph_func_t func; + void *user_data; + hb_destroy_func_t destroy; +}; +static hb_bool_t +hb_font_draw_glyph_trampoline (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data) +{ + hb_draw_glyph_closure_t *closure = (hb_draw_glyph_closure_t *) user_data; + closure->func (font, font_data, glyph, draw_funcs, draw_data, closure->user_data); + return true; +} +static void +hb_font_draw_glyph_closure_destroy (void *user_data) +{ + hb_draw_glyph_closure_t *closure = (hb_draw_glyph_closure_t *) user_data; + + if (closure->destroy) + closure->destroy (closure->user_data); + hb_free (closure); +} +static void +_hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_draw_glyph_func_t func, + void *user_data, + hb_destroy_func_t destroy /* May be NULL. */) +{ + if (hb_object_is_immutable (ffuncs)) + { + if (destroy) + destroy (user_data); + return; + } + hb_draw_glyph_closure_t *closure = (hb_draw_glyph_closure_t *) hb_calloc (1, sizeof (hb_draw_glyph_closure_t)); + if (unlikely (!closure)) + { + if (destroy) + destroy (user_data); + return; + } + closure->func = func; + closure->user_data = user_data; + closure->destroy = destroy; + + hb_font_funcs_set_draw_glyph_or_fail_func (ffuncs, + hb_font_draw_glyph_trampoline, + closure, + hb_font_draw_glyph_closure_destroy); +} +void +hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_draw_glyph_func_t func, + void *user_data, + hb_destroy_func_t destroy /* May be NULL. */) +{ + _hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy); +} void hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_shape_func_t func, void *user_data, hb_destroy_func_t destroy /* May be NULL. */) { - hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy); + _hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy); +} + +struct hb_paint_glyph_closure_t +{ + hb_font_paint_glyph_func_t func; + void *user_data; + hb_destroy_func_t destroy; +}; +static hb_bool_t +hb_font_paint_glyph_trampoline (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, + void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) +{ + hb_paint_glyph_closure_t *closure = (hb_paint_glyph_closure_t *) user_data; + closure->func (font, font_data, glyph, paint_funcs, paint_data, palette, foreground, closure->user_data); + return true; +} +static void +hb_font_paint_glyph_closure_destroy (void *user_data) +{ + hb_paint_glyph_closure_t *closure = (hb_paint_glyph_closure_t *) user_data; + + if (closure->destroy) + closure->destroy (closure->user_data); + hb_free (closure); +} +void +hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_paint_glyph_func_t func, + void *user_data, + hb_destroy_func_t destroy /* May be NULL. */) +{ + if (hb_object_is_immutable (ffuncs)) + { + if (destroy) + destroy (user_data); + return; + } + hb_paint_glyph_closure_t *closure = (hb_paint_glyph_closure_t *) hb_calloc (1, sizeof (hb_paint_glyph_closure_t)); + if (unlikely (!closure)) + { + if (destroy) + destroy (user_data); + return; + } + closure->func = func; + closure->user_data = user_data; + closure->destroy = destroy; + + hb_font_funcs_set_paint_glyph_or_fail_func (ffuncs, + hb_font_paint_glyph_trampoline, + closure, + hb_font_paint_glyph_closure_destroy); } #endif diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-font.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-font.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.h 2025-10-13 07:49:24.000000000 +0000 @@ -486,7 +486,7 @@ void *user_data); /** - * hb_font_draw_glyph_func_t: + * hb_font_draw_glyph_or_fail_func_t: * @font: #hb_font_t to work upon * @font_data: @font user data pointer * @glyph: The glyph ID to query @@ -496,16 +496,17 @@ * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * - * Since: 7.0.0 + * Return value: `true` if glyph was drawn, `false` otherwise * + * XSince: REPLACEME **/ -typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data); +typedef hb_bool_t (*hb_font_draw_glyph_or_fail_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); /** - * hb_font_paint_glyph_func_t: + * hb_font_paint_glyph_or_fail_func_t: * @font: #hb_font_t to work upon * @font_data: @font user data pointer * @glyph: The glyph ID to query @@ -517,14 +518,16 @@ * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * - * Since: 7.0.0 + * Return value: `true` if glyph was painted, `false` otherwise + * + * XSince: REPLACEME */ -typedef void (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_paint_funcs_t *paint_funcs, void *paint_data, - unsigned int palette_index, - hb_color_t foreground, - void *user_data); +typedef hb_bool_t (*hb_font_paint_glyph_or_fail_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data); /* func setters */ @@ -785,36 +788,36 @@ void *user_data, hb_destroy_func_t destroy); /** - * hb_font_funcs_set_draw_glyph_func: + * hb_font_funcs_set_draw_glyph_or_fail_func: * @ffuncs: A font-function structure * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign * @user_data: Data to pass to @func * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * Sets the implementation function for #hb_font_draw_glyph_func_t. + * Sets the implementation function for #hb_font_draw_glyph_or_fail_func_t. * - * Since: 7.0.0 + * XSince: REPLACEME **/ HB_EXTERN void -hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs, - hb_font_draw_glyph_func_t func, - void *user_data, hb_destroy_func_t destroy); +hb_font_funcs_set_draw_glyph_or_fail_func (hb_font_funcs_t *ffuncs, + hb_font_draw_glyph_or_fail_func_t func, + void *user_data, hb_destroy_func_t destroy); /** - * hb_font_funcs_set_paint_glyph_func: + * hb_font_funcs_set_paint_glyph_or_fail_func: * @ffuncs: A font-function structure * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign * @user_data: Data to pass to @func * @destroy: (nullable): The function to call when @user_data is no longer needed * - * Sets the implementation function for #hb_font_paint_glyph_func_t. + * Sets the implementation function for #hb_font_paint_glyph_or_fail_func_t. * - * Since: 7.0.0 + * XSince: REPLACEME */ HB_EXTERN void -hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs, - hb_font_paint_glyph_func_t func, - void *user_data, hb_destroy_func_t destroy); +hb_font_funcs_set_paint_glyph_or_fail_func (hb_font_funcs_t *ffuncs, + hb_font_paint_glyph_or_fail_func_t func, + void *user_data, hb_destroy_func_t destroy); /* func dispatch */ @@ -896,17 +899,17 @@ const char *name, int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph); -HB_EXTERN void -hb_font_draw_glyph (hb_font_t *font, - hb_codepoint_t glyph, - hb_draw_funcs_t *dfuncs, void *draw_data); +HB_EXTERN hb_bool_t +hb_font_draw_glyph_or_fail (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); -HB_EXTERN void -hb_font_paint_glyph (hb_font_t *font, - hb_codepoint_t glyph, - hb_paint_funcs_t *pfuncs, void *paint_data, - unsigned int palette_index, - hb_color_t foreground); +HB_EXTERN hb_bool_t +hb_font_paint_glyph_or_fail (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground); /* high-level funcs, with fallback */ @@ -979,6 +982,19 @@ const char *s, int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph); +/* Older alias for hb_font_draw_glyph_or_fail() with no return value. */ +HB_EXTERN void +hb_font_draw_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); + +/* Paints color glyph; if failed, draws outline glyph. */ +HB_EXTERN void +hb_font_paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground); /* * hb_font_t @@ -1052,6 +1068,12 @@ void *font_data, hb_destroy_func_t destroy); +HB_EXTERN hb_bool_t +hb_font_set_funcs_using (hb_font_t *font, + const char *name); + +HB_EXTERN const char ** +hb_font_list_funcs (void); HB_EXTERN void hb_font_set_scale (hb_font_t *font, @@ -1086,6 +1108,9 @@ HB_EXTERN float hb_font_get_ptem (hb_font_t *font); +HB_EXTERN hb_bool_t +hb_font_is_synthetic (hb_font_t *font); + HB_EXTERN void hb_font_set_synthetic_bold (hb_font_t *font, float x_embolden, float y_embolden, diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-font.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-font.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-font.hh 2025-10-13 07:49:24.000000000 +0000 @@ -32,7 +32,11 @@ #include "hb.hh" #include "hb-face.hh" +#include "hb-atomic.hh" +#include "hb-draw.hh" +#include "hb-paint-extents.hh" #include "hb-shaper.hh" +#include "hb-outline.hh" /* @@ -57,8 +61,8 @@ HB_FONT_FUNC_IMPLEMENT (get_,glyph_contour_point) \ HB_FONT_FUNC_IMPLEMENT (get_,glyph_name) \ HB_FONT_FUNC_IMPLEMENT (get_,glyph_from_name) \ - HB_FONT_FUNC_IMPLEMENT (,draw_glyph) \ - HB_FONT_FUNC_IMPLEMENT (,paint_glyph) \ + HB_FONT_FUNC_IMPLEMENT (,draw_glyph_or_fail) \ + HB_FONT_FUNC_IMPLEMENT (,paint_glyph_or_fail) \ /* ^--- Add new callbacks here */ struct hb_font_funcs_t @@ -105,8 +109,8 @@ struct hb_font_t { hb_object_header_t header; - unsigned int serial; - unsigned int serial_coords; + hb_atomic_t serial; + hb_atomic_t serial_coords; hb_font_t *parent; hb_face_t *face; @@ -191,23 +195,35 @@ void scale_glyph_extents (hb_glyph_extents_t *extents) { - float x1 = em_fscale_x (extents->x_bearing); - float y1 = em_fscale_y (extents->y_bearing); - float x2 = em_fscale_x (extents->x_bearing + extents->width); - float y2 = em_fscale_y (extents->y_bearing + extents->height); + float x1 = em_scale_x (extents->x_bearing); + float y1 = em_scale_y (extents->y_bearing); + float x2 = em_scale_x (extents->x_bearing + extents->width); + float y2 = em_scale_y (extents->y_bearing + extents->height); - /* Apply slant. */ + extents->x_bearing = roundf (x1); + extents->y_bearing = roundf (y1); + extents->width = roundf (x2) - extents->x_bearing; + extents->height = roundf (y2) - extents->y_bearing; + } + + void synthetic_glyph_extents (hb_glyph_extents_t *extents) + { + /* Slant. */ if (slant_xy) { - x1 += hb_min (y1 * slant_xy, y2 * slant_xy); - x2 += hb_max (y1 * slant_xy, y2 * slant_xy); - } + hb_position_t x1 = extents->x_bearing; + hb_position_t y1 = extents->y_bearing; + hb_position_t x2 = extents->x_bearing + extents->width; + hb_position_t y2 = extents->y_bearing + extents->height; + + x1 += floorf (hb_min (y1 * slant_xy, y2 * slant_xy)); + x2 += ceilf (hb_max (y1 * slant_xy, y2 * slant_xy)); - extents->x_bearing = floorf (x1); - extents->y_bearing = floorf (y1); - extents->width = ceilf (x2) - extents->x_bearing; - extents->height = ceilf (y2) - extents->y_bearing; + extents->x_bearing = x1; + extents->width = x2 - extents->x_bearing; + } + /* Embolden. */ if (x_strength || y_strength) { /* Y */ @@ -250,19 +266,45 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT - hb_bool_t get_font_h_extents (hb_font_extents_t *extents) + hb_bool_t get_font_h_extents (hb_font_extents_t *extents, + bool synthetic = true) { hb_memset (extents, 0, sizeof (*extents)); - return klass->get.f.font_h_extents (this, user_data, - extents, - !klass->user_data ? nullptr : klass->user_data->font_h_extents); + bool ret = klass->get.f.font_h_extents (this, user_data, + extents, + !klass->user_data ? nullptr : klass->user_data->font_h_extents); + + if (synthetic && ret) + { + /* Embolden */ + int y_shift = y_scale < 0 ? -y_strength : y_strength; + extents->ascender += y_shift; + } + + return ret; } - hb_bool_t get_font_v_extents (hb_font_extents_t *extents) + hb_bool_t get_font_v_extents (hb_font_extents_t *extents, + bool synthetic = true) { hb_memset (extents, 0, sizeof (*extents)); - return klass->get.f.font_v_extents (this, user_data, - extents, - !klass->user_data ? nullptr : klass->user_data->font_v_extents); + bool ret = klass->get.f.font_v_extents (this, user_data, + extents, + !klass->user_data ? nullptr : klass->user_data->font_v_extents); + + if (synthetic && ret) + { + /* Embolden */ + int x_shift = x_scale < 0 ? -x_strength : x_strength; + if (embolden_in_place) + { + extents->ascender += x_shift / 2; + extents->descender -= x_shift - x_shift / 2; + } + else + extents->ascender += x_shift; + } + + return ret; } bool has_glyph (hb_codepoint_t unicode) @@ -303,44 +345,88 @@ !klass->user_data ? nullptr : klass->user_data->variation_glyph); } - hb_position_t get_glyph_h_advance (hb_codepoint_t glyph) + hb_position_t get_glyph_h_advance (hb_codepoint_t glyph, + bool synthetic = true) { - return klass->get.f.glyph_h_advance (this, user_data, - glyph, - !klass->user_data ? nullptr : klass->user_data->glyph_h_advance); + hb_position_t advance = klass->get.f.glyph_h_advance (this, user_data, + glyph, + !klass->user_data ? nullptr : klass->user_data->glyph_h_advance); + + if (synthetic && x_strength && !embolden_in_place) + { + /* Embolden */ + hb_position_t strength = x_scale >= 0 ? x_strength : -x_strength; + advance += advance ? strength : 0; + } + + return advance; } - hb_position_t get_glyph_v_advance (hb_codepoint_t glyph) + hb_position_t get_glyph_v_advance (hb_codepoint_t glyph, + bool synthetic = true) { - return klass->get.f.glyph_v_advance (this, user_data, - glyph, - !klass->user_data ? nullptr : klass->user_data->glyph_v_advance); + hb_position_t advance = klass->get.f.glyph_v_advance (this, user_data, + glyph, + !klass->user_data ? nullptr : klass->user_data->glyph_v_advance); + + if (synthetic && y_strength && !embolden_in_place) + { + /* Embolden */ + hb_position_t strength = y_scale >= 0 ? y_strength : -y_strength; + advance += advance ? strength : 0; + } + + return advance; } void get_glyph_h_advances (unsigned int count, const hb_codepoint_t *first_glyph, unsigned int glyph_stride, hb_position_t *first_advance, - unsigned int advance_stride) + unsigned int advance_stride, + bool synthetic = true) { - return klass->get.f.glyph_h_advances (this, user_data, - count, - first_glyph, glyph_stride, - first_advance, advance_stride, - !klass->user_data ? nullptr : klass->user_data->glyph_h_advances); + klass->get.f.glyph_h_advances (this, user_data, + count, + first_glyph, glyph_stride, + first_advance, advance_stride, + !klass->user_data ? nullptr : klass->user_data->glyph_h_advances); + + if (synthetic && x_strength && !embolden_in_place) + { + /* Embolden */ + hb_position_t strength = x_scale >= 0 ? x_strength : -x_strength; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } void get_glyph_v_advances (unsigned int count, const hb_codepoint_t *first_glyph, unsigned int glyph_stride, hb_position_t *first_advance, - unsigned int advance_stride) + unsigned int advance_stride, + bool synthetic = true) { - return klass->get.f.glyph_v_advances (this, user_data, - count, - first_glyph, glyph_stride, - first_advance, advance_stride, - !klass->user_data ? nullptr : klass->user_data->glyph_v_advances); + klass->get.f.glyph_v_advances (this, user_data, + count, + first_glyph, glyph_stride, + first_advance, advance_stride, + !klass->user_data ? nullptr : klass->user_data->glyph_v_advances); + + if (synthetic && y_strength && !embolden_in_place) + { + /* Embolden */ + hb_position_t strength = y_scale >= 0 ? y_strength : -y_strength; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, @@ -386,23 +472,82 @@ } hb_bool_t get_glyph_extents (hb_codepoint_t glyph, - hb_glyph_extents_t *extents) + hb_glyph_extents_t *extents, + bool synthetic = true) { hb_memset (extents, 0, sizeof (*extents)); - return klass->get.f.glyph_extents (this, user_data, - glyph, - extents, - !klass->user_data ? nullptr : klass->user_data->glyph_extents); + + /* This is rather messy, but necessary. */ + + if (!synthetic) + { + return klass->get.f.glyph_extents (this, user_data, + glyph, + extents, + !klass->user_data ? nullptr : klass->user_data->glyph_extents); + } + if (!is_synthetic () && + klass->get.f.glyph_extents (this, user_data, + glyph, + extents, + !klass->user_data ? nullptr : klass->user_data->glyph_extents)) + return true; + + /* Try getting extents from paint(), then draw(), *then* get_extents() + * and apply synthetic settings in the last case. */ + + hb_paint_extents_context_t paint_extents; + if (paint_glyph_or_fail (glyph, + hb_paint_extents_get_funcs (), &paint_extents, + 0, 0)) + { + *extents = paint_extents.get_extents ().to_glyph_extents (); + return true; + } + + hb_extents_t draw_extents; + if (draw_glyph_or_fail (glyph, + hb_draw_extents_get_funcs (), &draw_extents)) + { + *extents = draw_extents.to_glyph_extents (); + return true; + } + + bool ret = klass->get.f.glyph_extents (this, user_data, + glyph, + extents, + !klass->user_data ? nullptr : klass->user_data->glyph_extents); + if (ret) + synthetic_glyph_extents (extents); + + return ret; } hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index, - hb_position_t *x, hb_position_t *y) + hb_position_t *x, hb_position_t *y, + bool synthetic = true) { *x = *y = 0; - return klass->get.f.glyph_contour_point (this, user_data, - glyph, point_index, - x, y, - !klass->user_data ? nullptr : klass->user_data->glyph_contour_point); + bool ret = klass->get.f.glyph_contour_point (this, user_data, + glyph, point_index, + x, y, + !klass->user_data ? nullptr : klass->user_data->glyph_contour_point); + + if (synthetic && ret) + { + /* Slant */ + if (slant_xy) + *x += roundf (*y * slant_xy); + + /* Embolden */ + if (!embolden_in_place) + { + int x_shift = x_scale < 0 ? -x_strength : x_strength; + *x += x_shift; + } + } + + return ret; } hb_bool_t get_glyph_name (hb_codepoint_t glyph, @@ -426,29 +571,88 @@ !klass->user_data ? nullptr : klass->user_data->glyph_from_name); } - void draw_glyph (hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data) - { - klass->get.f.draw_glyph (this, user_data, - glyph, - draw_funcs, draw_data, - !klass->user_data ? nullptr : klass->user_data->draw_glyph); + bool draw_glyph_or_fail (hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + bool synthetic = true) + { +#ifndef HB_NO_OUTLINE + bool embolden = x_strength || y_strength; + bool slanted = slant_xy; + synthetic = synthetic && (embolden || slanted); +#else + synthetic = false; +#endif + + if (!synthetic) + { + return klass->get.f.draw_glyph_or_fail (this, user_data, + glyph, + draw_funcs, draw_data, + !klass->user_data ? nullptr : klass->user_data->draw_glyph_or_fail); + } + +#ifndef HB_NO_OUTLINE + + hb_outline_t outline; + if (!klass->get.f.draw_glyph_or_fail (this, user_data, + glyph, + hb_outline_recording_pen_get_funcs (), &outline, + !klass->user_data ? nullptr : klass->user_data->draw_glyph_or_fail)) + return false; + + // Slant before embolden; produces nicer results. + + if (slanted) + outline.slant (slant_xy); + + if (embolden) + { + float x_shift = embolden_in_place ? 0 : (float) x_strength / 2; + float y_shift = (float) y_strength / 2; + if (x_scale < 0) x_shift = -x_shift; + if (y_scale < 0) y_shift = -y_shift; + outline.embolden (x_strength, y_strength, x_shift, y_shift); + } + + outline.replay (draw_funcs, draw_data); + + return true; +#endif } - void paint_glyph (hb_codepoint_t glyph, - hb_paint_funcs_t *paint_funcs, void *paint_data, - unsigned int palette, - hb_color_t foreground) - { - klass->get.f.paint_glyph (this, user_data, - glyph, - paint_funcs, paint_data, - palette, foreground, - !klass->user_data ? nullptr : klass->user_data->paint_glyph); + bool paint_glyph_or_fail (hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground, + bool synthetic = true) + { + /* Slant */ + if (synthetic && slant_xy) + hb_paint_push_transform (paint_funcs, paint_data, + 1.f, 0.f, + slant_xy, 1.f, + 0.f, 0.f); + + bool ret = klass->get.f.paint_glyph_or_fail (this, user_data, + glyph, + paint_funcs, paint_data, + palette, foreground, + !klass->user_data ? nullptr : klass->user_data->paint_glyph_or_fail); + + if (synthetic && slant_xy) + hb_paint_pop_transform (paint_funcs, paint_data); + + return ret; } /* A bit higher-level, and with fallback */ + HB_INTERNAL + void paint_glyph (hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground); + void get_h_extents_with_fallback (hb_font_extents_t *extents) { if (!get_font_h_extents (extents)) @@ -686,7 +890,12 @@ return false; } - void mults_changed () + bool is_synthetic () const + { + return x_embolden || y_embolden || slant; + } + + void changed () { float upem = face->get_upem (); @@ -697,12 +906,14 @@ bool y_neg = y_scale < 0; y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem; - x_strength = fabsf (roundf (x_scale * x_embolden)); - y_strength = fabsf (roundf (y_scale * y_embolden)); + x_strength = roundf (abs (x_scale) * x_embolden); + y_strength = roundf (abs (y_scale) * y_embolden); slant_xy = y_scale ? slant * x_scale / y_scale : 0.f; data.fini (); + + serial++; } hb_position_t em_mult (int16_t v, int64_t mult) diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ft.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ft.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ft.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ft.cc 2025-10-13 07:49:24.000000000 +0000 @@ -37,11 +37,7 @@ #include "hb-draw.hh" #include "hb-font.hh" #include "hb-machinery.hh" -#ifndef HB_NO_AAT -#include "hb-aat-layout-trak-table.hh" -#endif #include "hb-ot-os2-table.hh" -#include "hb-ot-stat-table.hh" #include "hb-ot-shaper-arabic-pua.hh" #include "hb-paint.hh" @@ -101,7 +97,7 @@ mutable hb_mutex_t lock; /* Protects members below. */ FT_Face ft_face; - mutable unsigned cached_serial; + mutable hb_atomic_t cached_serial; mutable hb_ft_advance_cache_t advance_cache; }; @@ -118,7 +114,7 @@ ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; - ft_font->cached_serial = (unsigned) -1; + ft_font->cached_serial = UINT_MAX; new (&ft_font->advance_cache) hb_ft_advance_cache_t; return ft_font; @@ -213,9 +209,10 @@ { if (font->serial != ft_font->cached_serial) { + hb_lock_t lock (ft_font->lock); _hb_ft_hb_font_changed (font, ft_font->ft_face); ft_font->advance_cache.clear (); - ft_font->cached_serial = font->serial; + ft_font->cached_serial.set_release (font->serial.get_acquire ()); return true; } return false; @@ -478,7 +475,8 @@ void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; - hb_position_t *orig_first_advance = first_advance; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; int load_flags = ft_font->load_flags; @@ -519,38 +517,6 @@ first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } - - if (font->x_strength && !font->embolden_in_place) - { - /* Emboldening. */ - hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; - first_advance = orig_first_advance; - for (unsigned int i = 0; i < count; i++) - { - *first_advance += *first_advance ? x_strength : 0; - first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); - } - } - -#ifndef HB_NO_AAT - /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */ -#ifndef HB_NO_STYLE - bool apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data (); -#else - bool apply_trak = false; -#endif - if (apply_trak) - { - hb_position_t tracking = font->face->table.trak->get_h_tracking (font); - first_advance = orig_first_advance; - for (unsigned int i = 0; i < count; i++) - { - *first_advance += tracking; - first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); - first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); - } - } -#endif } #ifndef HB_NO_VERTICAL @@ -561,6 +527,8 @@ void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Fixed v; float y_mult; @@ -581,26 +549,11 @@ if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) return 0; - v = (int) (y_mult * v); - /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ + v = ((-v + (1<<9)) >> 10); - hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; - v = ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength); - -#ifndef HB_NO_AAT - /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */ -#ifndef HB_NO_STYLE - bool apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data (); -#else - bool apply_trak = false; -#endif - if (apply_trak) - v += font->face->table.trak->get_v_tracking (font); -#endif - - return v; + return (hb_position_t) (y_mult * v); } #endif @@ -614,6 +567,8 @@ void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; float x_mult, y_mult; @@ -658,6 +613,8 @@ void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Vector kerningv; @@ -669,6 +626,41 @@ } #endif +static bool +hb_ft_is_colr_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t gid) +{ +#ifndef HB_NO_PAINT +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; + + + /* COLRv1 */ + FT_OpaquePaint paint = {0}; + if (FT_Get_Color_Glyph_Paint (ft_face, gid, + FT_COLOR_NO_ROOT_TRANSFORM, + &paint)) + return true; + + /* COLRv0 */ + FT_LayerIterator iterator; + FT_UInt layer_glyph_index; + FT_UInt layer_color_index; + iterator.p = NULL; + if (FT_Get_Color_Glyph_Layer (ft_face, + gid, + &layer_glyph_index, + &layer_color_index, + &iterator)) + return true; +#endif +#endif + + return false; +} + static hb_bool_t hb_ft_get_glyph_extents (hb_font_t *font, void *font_data, @@ -676,11 +668,17 @@ hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { + // FreeType doesn't return COLR glyph extents. + if (hb_ft_is_colr_glyph (font, font_data, glyph)) + return false; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; float x_mult, y_mult; - float slant_xy = font->slant_xy; + #ifdef HAVE_FT_GET_TRANSFORM if (ft_font->transform) { @@ -708,33 +706,10 @@ float x2 = x1 + x_mult * ft_face->glyph->metrics.width; float y2 = y1 + y_mult * -ft_face->glyph->metrics.height; - /* Apply slant. */ - if (slant_xy) - { - x1 += hb_min (y1 * slant_xy, y2 * slant_xy); - x2 += hb_max (y1 * slant_xy, y2 * slant_xy); - } - - extents->x_bearing = floorf (x1); - extents->y_bearing = floorf (y1); - extents->width = ceilf (x2) - extents->x_bearing; - extents->height = ceilf (y2) - extents->y_bearing; - - if (font->x_strength || font->y_strength) - { - /* Y */ - int y_shift = font->y_strength; - if (font->y_scale < 0) y_shift = -y_shift; - extents->y_bearing += y_shift; - extents->height -= y_shift; - - /* X */ - int x_shift = font->x_strength; - if (font->x_scale < 0) x_shift = -x_shift; - if (font->embolden_in_place) - extents->x_bearing -= x_shift / 2; - extents->width += x_shift; - } + extents->x_bearing = roundf (x1); + extents->y_bearing = roundf (y1); + extents->width = roundf (x2) - extents->x_bearing; + extents->height = roundf (y2) - extents->y_bearing; return true; } @@ -749,6 +724,8 @@ void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; @@ -826,6 +803,8 @@ void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; float y_mult; @@ -857,7 +836,7 @@ metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender); } - metrics->ascender = (hb_position_t) (y_mult * (metrics->ascender + font->y_strength)); + metrics->ascender = (hb_position_t) (y_mult * metrics->ascender); metrics->descender = (hb_position_t) (y_mult * metrics->descender); metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap); @@ -908,23 +887,25 @@ return FT_Err_Ok; } -static void -hb_ft_draw_glyph (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data HB_UNUSED) +static hb_bool_t +hb_ft_draw_glyph_or_fail (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; if (unlikely (FT_Load_Glyph (ft_face, glyph, FT_LOAD_NO_BITMAP | ft_font->load_flags))) - return; + return false; if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) - return; + return false; const FT_Outline_Funcs outline_funcs = { _hb_ft_move_to, @@ -935,43 +916,13 @@ 0, /* delta */ }; - hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); - - /* Embolden */ - if (font->x_strength || font->y_strength) - { - FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_strength, font->y_strength); - - int x_shift = 0; - int y_shift = 0; - if (font->embolden_in_place) - { - /* Undo the FreeType shift. */ - x_shift = -font->x_strength / 2; - y_shift = 0; - if (font->y_scale < 0) y_shift = -font->y_strength; - } - else - { - /* FreeType applied things in the wrong direction for negative scale; fix up. */ - if (font->x_scale < 0) x_shift = -font->x_strength; - if (font->y_scale < 0) y_shift = -font->y_strength; - } - if (x_shift || y_shift) - { - auto &outline = ft_face->glyph->outline; - for (auto &point : hb_iter (outline.points, outline.contours[outline.n_contours - 1] + 1)) - { - point.x += x_shift; - point.y += y_shift; - } - } - } - + hb_draw_session_t draw_session {draw_funcs, draw_data}; FT_Outline_Decompose (&ft_face->glyph->outline, &outline_funcs, &draw_session); + + return true; } #endif @@ -980,20 +931,22 @@ #include "hb-ft-colr.hh" -static void -hb_ft_paint_glyph (hb_font_t *font, - void *font_data, - hb_codepoint_t gid, - hb_paint_funcs_t *paint_funcs, void *paint_data, - unsigned int palette_index, - hb_color_t foreground, - void *user_data) +static hb_bool_t +hb_ft_paint_glyph_or_fail (hb_font_t *font, + void *font_data, + hb_codepoint_t gid, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + _hb_ft_hb_font_check_changed (font, ft_font); + hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; - FT_Long load_flags = ft_font->load_flags | FT_LOAD_NO_BITMAP | FT_LOAD_COLOR; + FT_Long load_flags = ft_font->load_flags | FT_LOAD_COLOR; #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21301 load_flags |= FT_LOAD_NO_SVG; #endif @@ -1002,7 +955,7 @@ * eg. draw API can call back into the face.*/ if (unlikely (FT_Load_Glyph (ft_face, gid, load_flags))) - return; + return false; if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { @@ -1010,26 +963,21 @@ paint_funcs, paint_data, palette_index, foreground, user_data)) - return; - - /* Simple outline. */ - ft_font->lock.unlock (); - paint_funcs->push_clip_glyph (paint_data, gid, font); - ft_font->lock.lock (); - paint_funcs->color (paint_data, true, foreground); - paint_funcs->pop_clip (paint_data); + return true; - return; + // Outline glyph + return false; } auto *glyph = ft_face->glyph; if (glyph->format == FT_GLYPH_FORMAT_BITMAP) { + bool ret = false; auto &bitmap = glyph->bitmap; if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) { if (bitmap.pitch != (signed) bitmap.width * 4) - return; + return ret; ft_font->lock.unlock (); @@ -1039,27 +987,26 @@ nullptr, nullptr); hb_glyph_extents_t extents; - if (!hb_font_get_glyph_extents (font, gid, &extents)) + if (!font->get_glyph_extents (gid, &extents, false)) goto out; - if (!paint_funcs->image (paint_data, - blob, - bitmap.width, - bitmap.rows, - HB_PAINT_IMAGE_FORMAT_BGRA, - font->slant_xy, - &extents)) - { - /* TODO Try a forced outline load and paint? */ - } + if (paint_funcs->image (paint_data, + blob, + bitmap.width, + bitmap.rows, + HB_PAINT_IMAGE_FORMAT_BGRA, + 0.f, + &extents)) + ret = true; out: hb_blob_destroy (blob); ft_font->lock.lock (); } - return; + return ret; } + return false; } #endif #endif @@ -1079,10 +1026,8 @@ hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr); hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr); - //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr); #ifndef HB_NO_VERTICAL - //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr); hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr); hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr); #endif @@ -1090,19 +1035,18 @@ #ifndef HB_NO_OT_SHAPE_FALLBACK hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr); #endif - //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr); hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr); hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr); hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr); hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr); #ifndef HB_NO_DRAW - hb_font_funcs_set_draw_glyph_func (funcs, hb_ft_draw_glyph, nullptr, nullptr); + hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ft_draw_glyph_or_fail, nullptr, nullptr); #endif #ifndef HB_NO_PAINT #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 - hb_font_funcs_set_paint_glyph_func (funcs, hb_ft_paint_glyph, nullptr, nullptr); + hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ft_paint_glyph_or_fail, nullptr, nullptr); #endif #endif @@ -1456,6 +1400,10 @@ * variation-axis settings on the @font. * This call is fast if nothing has changed on @font. * + * Note that as of version 11.0.0, calling this function is not necessary, + * as HarfBuzz will automatically detect changes to the font and update + * the underlying FT_Face as needed. + * * Return value: true if changed, false otherwise * * Since: 4.4.0 @@ -1587,7 +1535,8 @@ * font file and face index. * * This is similar in functionality to hb_face_create_from_file_or_fail(), - * but uses the FreeType library for loading the font file. + * but uses the FreeType library for loading the font file. This can + * be useful, for example, to load WOFF and WOFF2 font data. * * Return value: (transfer full): The new face object, or `NULL` if * no face is found at the specified index or the file cannot be read. @@ -1623,6 +1572,75 @@ return face; } + +static hb_user_data_key_t ft_blob_key = {0}; + +static void +_destroy_blob (void *p) +{ + hb_blob_destroy ((hb_blob_t *) p); +} + +/** + * hb_ft_face_create_from_blob_or_fail: + * @blob: A blob + * @index: The index of the face within the blob + * + * Creates an #hb_face_t face object from the specified + * font blob and face index. + * + * This is similar in functionality to hb_face_create_from_blob_or_fail(), + * but uses the FreeType library for loading the font blob. This can + * be useful, for example, to load WOFF and WOFF2 font data. + * + * Return value: (transfer full): The new face object, or `NULL` if + * loading fails (eg. blob does not contain valid font data). + * + * Since: 11.0.0 + */ +hb_face_t * +hb_ft_face_create_from_blob_or_fail (hb_blob_t *blob, + unsigned int index) +{ + FT_Library ft_library = reference_ft_library (); + if (unlikely (!ft_library)) + { + DEBUG_MSG (FT, ft_library, "reference_ft_library failed"); + return nullptr; + } + + hb_blob_make_immutable (blob); + unsigned blob_size; + const char *blob_data = hb_blob_get_data (blob, &blob_size); + + FT_Face ft_face; + if (unlikely (FT_New_Memory_Face (ft_library, + (const FT_Byte *) blob_data, + blob_size, + index, + &ft_face))) + return nullptr; + + hb_face_t *face = hb_ft_face_create_referenced (ft_face); + FT_Done_Face (ft_face); + + ft_face->generic.data = ft_library; + ft_face->generic.finalizer = finalize_ft_library; + + if (hb_face_is_immutable (face)) + return nullptr; + + // Hook the blob to the hb_face_t, since FT_Face still needs it. + hb_blob_reference (blob); + if (!hb_face_set_user_data (face, &ft_blob_key, blob, _destroy_blob, true)) + { + hb_blob_destroy (blob); + hb_face_destroy (face); + return nullptr; + } + + return face; +} static void _release_blob (void *arg) diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ft.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ft.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ft.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ft.h 2025-10-13 07:49:24.000000000 +0000 @@ -88,6 +88,10 @@ hb_ft_face_create_from_file_or_fail (const char *file_name, unsigned int index); +HB_EXTERN hb_face_t * +hb_ft_face_create_from_blob_or_fail (hb_blob_t *blob, + unsigned int index); + /* * hb-font from ft-face. */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh 2025-10-13 07:49:24.000000000 +0000 @@ -30,6 +30,11 @@ struct hb_extents_t { hb_extents_t () {} + hb_extents_t (const hb_glyph_extents_t &extents) : + xmin (hb_min (extents.x_bearing, extents.x_bearing + extents.width)), + ymin (hb_min (extents.y_bearing, extents.y_bearing + extents.height)), + xmax (hb_max (extents.x_bearing, extents.x_bearing + extents.width)), + ymax (hb_max (extents.y_bearing, extents.y_bearing + extents.height)) {} hb_extents_t (float xmin, float ymin, float xmax, float ymax) : xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {} @@ -38,6 +43,12 @@ void union_ (const hb_extents_t &o) { + if (o.is_empty ()) return; + if (is_empty ()) + { + *this = o; + return; + } xmin = hb_min (xmin, o.xmin); ymin = hb_min (ymin, o.ymin); xmax = hb_max (xmax, o.xmax); @@ -46,6 +57,11 @@ void intersect (const hb_extents_t &o) { + if (o.is_empty () || is_empty ()) + { + *this = hb_extents_t {}; + return; + } xmin = hb_max (xmin, o.xmin); ymin = hb_max (ymin, o.ymin); xmax = hb_min (xmax, o.xmax); @@ -69,6 +85,18 @@ } } + hb_glyph_extents_t to_glyph_extents (bool xneg = false, bool yneg = false) const + { + hb_position_t x0 = (hb_position_t) roundf (xmin); + hb_position_t y0 = (hb_position_t) roundf (ymin); + hb_position_t x1 = (hb_position_t) roundf (xmax); + hb_position_t y1 = (hb_position_t) roundf (ymax); + return hb_glyph_extents_t {xneg ? x1 : x0, + yneg ? y0 : y1, + xneg ? x0 - x1 : x1 - x0, + yneg ? y1 - y0 : y0 - y1}; + } + float xmin = 0.f; float ymin = 0.f; float xmax = -1.f; @@ -218,7 +246,7 @@ EMPTY, }; - hb_bounds_t (status_t status) : status (status) {} + hb_bounds_t (status_t status = UNBOUNDED) : status (status) {} hb_bounds_t (const hb_extents_t &extents) : status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {} diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh 2025-10-13 07:49:24.000000000 +0000 @@ -273,7 +273,7 @@ private: /* Must only have one pointer. */ - hb_atomic_ptr_t instance; + mutable hb_atomic_t instance; }; /* Specializations. */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh 2025-10-13 07:49:24.000000000 +0000 @@ -99,6 +99,8 @@ hb_mutex_t () { init (); } ~hb_mutex_t () { fini (); } + hb_mutex_t (const hb_mutex_t &) = delete; + hb_mutex_t &operator= (const hb_mutex_t &) = delete; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" @@ -114,6 +116,10 @@ hb_lock_t (hb_mutex_t &mutex_) : mutex (&mutex_) { mutex->lock (); } hb_lock_t (hb_mutex_t *mutex_) : mutex (mutex_) { if (mutex) mutex->lock (); } ~hb_lock_t () { if (mutex) mutex->unlock (); } + + hb_lock_t (const hb_lock_t &) = delete; + hb_lock_t &operator= (const hb_lock_t &) = delete; + private: hb_mutex_t *mutex; }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-object.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-object.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-object.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-object.hh 2025-10-13 07:49:24.000000000 +0000 @@ -142,7 +142,7 @@ struct hb_reference_count_t { - mutable hb_atomic_int_t ref_count; + mutable hb_atomic_t ref_count; void init (int v = 1) { ref_count = v; } int get_relaxed () const { return ref_count; } @@ -213,8 +213,8 @@ struct hb_object_header_t { hb_reference_count_t ref_count; - mutable hb_atomic_int_t writable = 0; - hb_atomic_ptr_t user_data; + mutable hb_atomic_t writable = false; + hb_atomic_t user_data; bool is_inert () const { return !ref_count.get_relaxed (); } }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh 2025-10-13 07:49:24.000000000 +0000 @@ -1888,7 +1888,7 @@ bool ensure_run () { - if (likely (run_count > 0)) return true; + if (run_count > 0) return true; if (unlikely (p >= end)) { @@ -1943,6 +1943,11 @@ unsigned count = hb_min (n - i, (unsigned) run_count); switch (width) { + case 0: + { + arrayZ += count; + break; + } case 1: { const auto *pp = (const HBINT8 *) p; @@ -1958,6 +1963,8 @@ #endif for (; j < count; j++) *arrayZ++ += scaled ? *pp++ * scale : *pp++; + + p = (const unsigned char *) pp; } break; case 2: @@ -1975,6 +1982,8 @@ #endif for (; j < count; j++) *arrayZ++ += scaled ? *pp++ * scale : *pp++; + + p = (const unsigned char *) pp; } break; case 4: @@ -1982,10 +1991,11 @@ const auto *pp = (const HBINT32 *) p; for (unsigned j = 0; j < count; j++) *arrayZ++ += scaled ? *pp++ * scale : *pp++; + + p = (const unsigned char *) pp; } break; } - p += count * width; run_count -= count; i += count; } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -1073,7 +1073,7 @@ this->blob = sc.reference_table (face); - /* setup for run-time santization */ + /* setup for run-time sanitization */ sc.init (this->blob); sc.start_processing (); @@ -1176,7 +1176,8 @@ if (unlikely (!font_interp.interpret (*font))) goto fail; PRIVDICTVAL *priv = &privateDicts[i]; const hb_ubytes_t privDictStr = StructAtOffsetOrNull (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size); - if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; + if (unlikely (font->privateDictInfo.size && + privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; num_interp_env_t env2 (privDictStr); dict_interpreter_t priv_interp (env2); priv->init (); @@ -1191,7 +1192,8 @@ PRIVDICTVAL *priv = &privateDicts[0]; const hb_ubytes_t privDictStr = StructAtOffsetOrNull (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size); - if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; + if (font->privateDictInfo.size && + unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; num_interp_env_t env (privDictStr); dict_interpreter_t priv_interp (env); priv->init (); @@ -1483,7 +1485,7 @@ int cmp (const gname_t &a) const { return cmp (&a, this); } }; - mutable hb_atomic_ptr_t> glyph_names; + mutable hb_atomic_t *> glyph_names; typedef accelerator_templ_t SUPER; }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc 2025-10-13 07:49:24.000000000 +0000 @@ -103,6 +103,14 @@ hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { + return get_extents_at (font, glyph, extents, hb_array (font->coords, font->num_coords)); +} + +bool OT::cff2::accelerator_t::get_extents_at (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + hb_array_t coords) const +{ #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ return true; @@ -112,7 +120,7 @@ unsigned int fd = fdSelect->get_fd (glyph); const hb_ubytes_t str = (*charStrings)[glyph]; - cff2_cs_interp_env_t env (str, *this, fd, font->coords, font->num_coords); + cff2_cs_interp_env_t env (str, *this, fd, coords.arrayZ, coords.length); cff2_cs_interpreter_t interp (env); cff2_extents_param_t param; if (unlikely (!interp.interpret (param))) return false; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -405,7 +405,7 @@ this->blob = sc.reference_table (face); - /* setup for run-time santization */ + /* setup for run-time sanitization */ sc.init (this->blob); sc.start_processing (); @@ -458,7 +458,8 @@ if (unlikely (!font_interp.interpret (*font))) goto fail; const hb_ubytes_t privDictStr = StructAtOffsetOrNull (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size); - if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; + if (unlikely (font->privateDictInfo.size && + privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; cff2_priv_dict_interp_env_t env2 (privDictStr); dict_interpreter_t priv_interp (env2); privateDicts[i].init (); @@ -481,6 +482,13 @@ privateDicts.fini (); hb_blob_destroy (blob); blob = nullptr; + + auto *scalars = cached_scalars_vector.get_acquire (); + if (scalars && cached_scalars_vector.cmpexch (scalars, nullptr)) + { + scalars->fini (); + hb_free (scalars); + } } hb_vector_t *create_glyph_to_sid_map () const @@ -508,6 +516,8 @@ hb_vector_t fontDicts; hb_vector_t privateDicts; + mutable hb_atomic_t *> cached_scalars_vector; + unsigned int num_glyphs = 0; }; @@ -518,6 +528,10 @@ HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool get_extents_at (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + hb_array_t coords) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords) const; }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -2014,7 +2014,8 @@ struct accelerator_t { - using cache_t = hb_cache_t<21, 16, 8, true>; + using cache_t = hb_cache_t<21, 19>; + static_assert (sizeof (cache_t) == 1024, ""); accelerator_t (hb_face_t *face) { @@ -2028,6 +2029,14 @@ subtable_uvs = &st->u.format14; } +#ifndef HB_NO_OT_FONT_CMAP_CACHE + cache = (cache_t *) hb_malloc (sizeof (cache_t)); + if (cache) + new (cache) cache_t (); + else + return; // Such that get_glyph_funcZ remains null. +#endif + this->get_glyph_data = subtable; #ifndef HB_NO_CMAP_LEGACY_SUBTABLES if (unlikely (symbol)) @@ -2061,62 +2070,71 @@ #endif { switch (subtable->u.format) { - /* Accelerate format 4 and format 12. */ - default: - this->get_glyph_funcZ = get_glyph_from; - break; - case 12: - this->get_glyph_funcZ = get_glyph_from; - break; - case 4: - { - this->format4_accel.init (&subtable->u.format4); - this->get_glyph_data = &this->format4_accel; - this->get_glyph_funcZ = this->format4_accel.get_glyph_func; - break; - } + /* Accelerate format 4 and format 12. */ + default: + this->get_glyph_funcZ = get_glyph_from; + break; + case 12: + this->get_glyph_funcZ = get_glyph_from; + break; + case 4: + { + this->format4_accel.init (&subtable->u.format4); + this->get_glyph_data = &this->format4_accel; + this->get_glyph_funcZ = this->format4_accel.get_glyph_func; + break; + } } } } - ~accelerator_t () { this->table.destroy (); } + ~accelerator_t () + { +#ifndef HB_NO_OT_FONT_CMAP_CACHE + hb_free (cache); +#endif + table.destroy (); + } inline bool _cached_get (hb_codepoint_t unicode, - hb_codepoint_t *glyph, - cache_t *cache) const + hb_codepoint_t *glyph) const { +#ifndef HB_NO_OT_FONT_CMAP_CACHE + // cache is always non-null if we have a get_glyph_funcZ unsigned v; - if (cache && cache->get (unicode, &v)) + if (cache->get (unicode, &v)) { *glyph = v; return true; } +#endif bool ret = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); - if (cache && ret) +#ifndef HB_NO_OT_FONT_CMAP_CACHE + if (ret) cache->set (unicode, *glyph); +#endif + return ret; } bool get_nominal_glyph (hb_codepoint_t unicode, - hb_codepoint_t *glyph, - cache_t *cache = nullptr) const + hb_codepoint_t *glyph) const { if (unlikely (!this->get_glyph_funcZ)) return false; - return _cached_get (unicode, glyph, cache); + return _cached_get (unicode, glyph); } unsigned int get_nominal_glyphs (unsigned int count, const hb_codepoint_t *first_unicode, unsigned int unicode_stride, hb_codepoint_t *first_glyph, - unsigned int glyph_stride, - cache_t *cache = nullptr) const + unsigned int glyph_stride) const { if (unlikely (!this->get_glyph_funcZ)) return 0; unsigned int done; for (done = 0; - done < count && _cached_get (*first_unicode, first_glyph, cache); + done < count && _cached_get (*first_unicode, first_glyph); done++) { first_unicode = &StructAtOffsetUnaligned (first_unicode, unicode_stride); @@ -2127,8 +2145,7 @@ bool get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, - hb_codepoint_t *glyph, - cache_t *cache = nullptr) const + hb_codepoint_t *glyph) const { switch (this->subtable_uvs->get_glyph_variant (unicode, variation_selector, @@ -2139,7 +2156,7 @@ case GLYPH_VARIANT_USE_DEFAULT: break; } - return get_nominal_glyph (unicode, glyph, cache); + return get_nominal_glyph (unicode, glyph); } void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const @@ -2209,11 +2226,15 @@ hb_nonnull_ptr_t subtable; hb_nonnull_ptr_t subtable_uvs; - hb_cmap_get_glyph_func_t get_glyph_funcZ; - const void *get_glyph_data; + hb_cmap_get_glyph_func_t get_glyph_funcZ = nullptr; + const void *get_glyph_data = nullptr; CmapSubtableFormat4::accelerator_t format4_accel; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + cache_t *cache = nullptr; +#endif + public: hb_blob_ptr_t table; }; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc 2025-10-13 07:49:24.000000000 +0000 @@ -204,7 +204,7 @@ hb_bool_t hb_ot_color_has_layers (hb_face_t *face) { - return face->table.COLR->has_v0_data (); + return face->table.COLR->colr->has_v0_data (); } /** @@ -221,7 +221,7 @@ hb_bool_t hb_ot_color_has_paint (hb_face_t *face) { - return face->table.COLR->has_v1_data (); + return face->table.COLR->colr->has_v1_data (); } /** @@ -240,7 +240,7 @@ hb_ot_color_glyph_has_paint (hb_face_t *face, hb_codepoint_t glyph) { - return face->table.COLR->has_paint_for_glyph (glyph); + return face->table.COLR->colr->has_paint_for_glyph (glyph); } /** @@ -266,7 +266,7 @@ unsigned int *layer_count, /* IN/OUT. May be NULL. */ hb_ot_color_layer_t *layers /* OUT. May be NULL. */) { - return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers); + return face->table.COLR->colr->get_glyph_layers (glyph, start_offset, layer_count, layers); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh 2025-10-13 07:49:24.000000000 +0000 @@ -136,7 +136,7 @@ /* OpenType color fonts. */ #ifndef HB_NO_COLOR -HB_OT_CORE_TABLE (OT, COLR) +HB_OT_ACCELERATOR (OT, COLR) HB_OT_CORE_TABLE (OT, CPAL) HB_OT_ACCELERATOR (OT, CBDT) HB_OT_ACCELERATOR (OT, sbix) diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc 2025-10-13 07:49:24.000000000 +0000 @@ -36,6 +36,7 @@ #include "hb-ot-name-table.hh" #include "hb-ot-post-table.hh" #include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/COLR/COLR.hh" #include "OT/Color/sbix/sbix.hh" #include "OT/Color/svg/svg.hh" #include "hb-ot-layout-gdef-table.hh" diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc 2025-10-13 07:49:24.000000000 +0000 @@ -34,11 +34,7 @@ #include "hb-font.hh" #include "hb-machinery.hh" #include "hb-ot-face.hh" -#include "hb-outline.hh" -#ifndef HB_NO_AAT -#include "hb-aat-layout-trak-table.hh" -#endif #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" #include "hb-ot-cff2-table.hh" @@ -65,28 +61,111 @@ * never need to call these functions directly. **/ -using hb_ot_font_cmap_cache_t = hb_cache_t<21, 16, 8, true>; -using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>; - -#ifndef HB_NO_OT_FONT_CMAP_CACHE -static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key; -#endif +using hb_ot_font_advance_cache_t = hb_cache_t<24, 16>; +static_assert (sizeof (hb_ot_font_advance_cache_t) == 1024, ""); struct hb_ot_font_t { const hb_ot_face_t *ot_face; -#ifndef HB_NO_AAT - bool apply_trak; -#endif + /* h_advance caching */ + mutable hb_atomic_t cached_coords_serial; + struct advance_cache_t + { + mutable hb_atomic_t advance_cache; + mutable hb_atomic_t varStore_cache; -#ifndef HB_NO_OT_FONT_CMAP_CACHE - hb_ot_font_cmap_cache_t *cmap_cache; -#endif + ~advance_cache_t () + { + clear (); + } - /* h_advance caching */ - mutable hb_atomic_int_t cached_coords_serial; - mutable hb_atomic_ptr_t advance_cache; + hb_ot_font_advance_cache_t *acquire_advance_cache () const + { + retry: + auto *cache = advance_cache.get_acquire (); + if (!cache) + { + cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t)); + if (!cache) + return nullptr; + new (cache) hb_ot_font_advance_cache_t; + return cache; + } + if (advance_cache.cmpexch (cache, nullptr)) + return cache; + else + goto retry; + } + void release_advance_cache (hb_ot_font_advance_cache_t *cache) const + { + if (!cache) + return; + if (!advance_cache.cmpexch (nullptr, cache)) + hb_free (cache); + } + void clear_advance_cache () const + { + retry: + auto *cache = advance_cache.get_acquire (); + if (!cache) + return; + if (advance_cache.cmpexch (cache, nullptr)) + hb_free (cache); + else + goto retry; + } + + OT::ItemVariationStore::cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const + { + retry: + auto *cache = varStore_cache.get_acquire (); + if (!cache) + return varStore.create_cache (); + if (varStore_cache.cmpexch (cache, nullptr)) + return cache; + else + goto retry; + } + void release_varStore_cache (OT::ItemVariationStore::cache_t *cache) const + { + if (!cache) + return; + if (!varStore_cache.cmpexch (nullptr, cache)) + OT::ItemVariationStore::destroy_cache (cache); + } + void clear_varStore_cache () const + { + retry: + auto *cache = varStore_cache.get_acquire (); + if (!cache) + return; + if (varStore_cache.cmpexch (cache, nullptr)) + OT::ItemVariationStore::destroy_cache (cache); + else + goto retry; + } + + void clear () const + { + clear_advance_cache (); + clear_varStore_cache (); + } + + } h, v; + + void check_serial (hb_font_t *font) const + { + int font_serial = font->serial_coords.get_acquire (); + + if (cached_coords_serial.get_acquire () == font_serial) + return; + + h.clear (); + v.clear (); + + cached_coords_serial.set_release (font_serial); + } }; static hb_ot_font_t * @@ -98,44 +177,6 @@ ot_font->ot_face = &font->face->table; -#ifndef HB_NO_AAT - /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */ -#ifndef HB_NO_STYLE - ot_font->apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data (); -#else - ot_font->apply_trak = false; -#endif -#endif - -#ifndef HB_NO_OT_FONT_CMAP_CACHE - // retry: - auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face, - &hb_ot_font_cmap_cache_user_data_key); - if (!cmap_cache) - { - cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t)); - if (unlikely (!cmap_cache)) goto out; - new (cmap_cache) hb_ot_font_cmap_cache_t (); - if (unlikely (!hb_face_set_user_data (font->face, - &hb_ot_font_cmap_cache_user_data_key, - cmap_cache, - hb_free, - false))) - { - hb_free (cmap_cache); - cmap_cache = nullptr; - /* Normally we would retry here, but that would - * infinite-loop if the face is the empty-face. - * Just let it go and this font will be uncached if it - * happened to collide with another thread creating the - * cache at the same time. */ - // goto retry; - } - } - out: - ot_font->cmap_cache = cmap_cache; -#endif - return ot_font; } @@ -144,8 +185,7 @@ { hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data; - auto *cache = ot_font->advance_cache.get_relaxed (); - hb_free (cache); + ot_font->~hb_ot_font_t (); hb_free (ot_font); } @@ -159,11 +199,7 @@ { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - hb_ot_font_cmap_cache_t *cmap_cache = nullptr; -#ifndef HB_NO_OT_FONT_CMAP_CACHE - cmap_cache = ot_font->cmap_cache; -#endif - return ot_face->cmap->get_nominal_glyph (unicode, glyph, cmap_cache); + return ot_face->cmap->get_nominal_glyph (unicode, glyph); } static unsigned int @@ -178,14 +214,9 @@ { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - hb_ot_font_cmap_cache_t *cmap_cache = nullptr; -#ifndef HB_NO_OT_FONT_CMAP_CACHE - cmap_cache = ot_font->cmap_cache; -#endif return ot_face->cmap->get_nominal_glyphs (count, first_unicode, unicode_stride, - first_glyph, glyph_stride, - cmap_cache); + first_glyph, glyph_stride); } static hb_bool_t @@ -198,13 +229,8 @@ { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - hb_ot_font_cmap_cache_t *cmap_cache = nullptr; -#ifndef HB_NO_OT_FONT_CMAP_CACHE - cmap_cache = ot_font->cmap_cache; -#endif return ot_face->cmap->get_variation_glyph (unicode, - variation_selector, glyph, - cmap_cache); + variation_selector, glyph); } static void @@ -216,47 +242,25 @@ unsigned advance_stride, void *user_data HB_UNUSED) { + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; - hb_position_t *orig_first_advance = first_advance; - -#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) + ot_font->check_serial (font); const OT::HVAR &HVAR = *hmtx.var_table; const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore; - OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr; + OT::ItemVariationStore::cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore); - bool use_cache = font->num_coords; -#else - OT::ItemVariationStore::cache_t *varStore_cache = nullptr; - bool use_cache = false; -#endif + hb_ot_font_advance_cache_t *advance_cache = nullptr; - hb_ot_font_advance_cache_t *cache = nullptr; + bool use_cache = font->num_coords; if (use_cache) { - retry: - cache = ot_font->advance_cache.get_acquire (); - if (unlikely (!cache)) - { - cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t)); - if (unlikely (!cache)) - { - use_cache = false; - goto out; - } - new (cache) hb_ot_font_advance_cache_t; - - if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache))) - { - hb_free (cache); - goto retry; - } - ot_font->cached_coords_serial.set_release (font->serial_coords); - } + advance_cache = ot_font->h.acquire_advance_cache (); + if (!advance_cache) + use_cache = false; } - out: if (!use_cache) { @@ -269,58 +273,26 @@ } else { /* Use cache. */ - if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords) - { - ot_font->advance_cache->clear (); - ot_font->cached_coords_serial.set_release (font->serial_coords); - } - for (unsigned int i = 0; i < count; i++) { hb_position_t v; unsigned cv; - if (ot_font->advance_cache->get (*first_glyph, &cv)) + if (advance_cache->get (*first_glyph, &cv)) v = cv; else { v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache); - ot_font->advance_cache->set (*first_glyph, v); + advance_cache->set (*first_glyph, v); } *first_advance = font->em_scale_x (v); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } - } - -#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) - OT::ItemVariationStore::destroy_cache (varStore_cache); -#endif - if (font->x_strength && !font->embolden_in_place) - { - /* Emboldening. */ - hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; - first_advance = orig_first_advance; - for (unsigned int i = 0; i < count; i++) - { - *first_advance += *first_advance ? x_strength : 0; - first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); - } + ot_font->h.release_advance_cache (advance_cache); } -#ifndef HB_NO_AAT - if (ot_font->apply_trak) - { - hb_position_t tracking = font->face->table.trak->get_h_tracking (font); - first_advance = orig_first_advance; - for (unsigned int i = 0; i < count; i++) - { - *first_advance += tracking; - first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); - first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); - } - } -#endif + ot_font->h.release_varStore_cache (varStore_cache); } #ifndef HB_NO_VERTICAL @@ -337,17 +309,13 @@ const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - hb_position_t *orig_first_advance = first_advance; - if (vmtx.has_data ()) { -#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) + ot_font->check_serial (font); const OT::VVAR &VVAR = *vmtx.var_table; const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore; - OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr; -#else - OT::ItemVariationStore::cache_t *varStore_cache = nullptr; -#endif + OT::ItemVariationStore::cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore); + // TODO Use advance_cache. for (unsigned int i = 0; i < count; i++) { @@ -356,9 +324,7 @@ first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } -#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) - OT::ItemVariationStore::destroy_cache (varStore_cache); -#endif + ot_font->v.release_varStore_cache (varStore_cache); } else { @@ -373,32 +339,6 @@ first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } - - if (font->y_strength && !font->embolden_in_place) - { - /* Emboldening. */ - hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; - first_advance = orig_first_advance; - for (unsigned int i = 0; i < count; i++) - { - *first_advance += *first_advance ? y_strength : 0; - first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); - } - } - -#ifndef HB_NO_AAT - if (ot_font->apply_trak) - { - hb_position_t tracking = font->face->table.trak->get_v_tracking (font); - first_advance = orig_first_advance; - for (unsigned int i = 0; i < count; i++) - { - *first_advance += tracking; - first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); - first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); - } - } -#endif } #endif @@ -435,7 +375,8 @@ } hb_glyph_extents_t extents = {0}; - if (ot_face->glyf->get_extents (font, glyph, &extents)) + + if (hb_font_get_glyph_extents (font, glyph, &extents)) { const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; int tsb = 0; @@ -448,7 +389,7 @@ hb_font_extents_t font_extents; font->get_h_extents_with_fallback (&font_extents); hb_position_t advance = font_extents.ascender - font_extents.descender; - int diff = advance - -extents.height; + hb_position_t diff = advance - -extents.height; *y = extents.y_bearing + (diff >> 1); return true; } @@ -478,6 +419,9 @@ #if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT) if (ot_face->COLR->get_extents (font, glyph, extents)) return true; #endif +#ifndef HB_NO_VAR_COMPOSITES + if (ot_face->VARC->get_extents (font, glyph, extents)) return true; +#endif if (ot_face->glyf->get_extents (font, glyph, extents)) return true; #ifndef HB_NO_OT_FONT_CFF if (ot_face->cff2->get_extents (font, glyph, extents)) return true; @@ -528,16 +472,9 @@ hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - bool ret = _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && - _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && - _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); - - /* Embolden */ - int y_shift = font->y_strength; - if (font->y_scale < 0) y_shift = -y_shift; - metrics->ascender += y_shift; - - return ret; + return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); } #ifndef HB_NO_VERTICAL @@ -554,68 +491,46 @@ #endif #ifndef HB_NO_DRAW -static void -hb_ot_draw_glyph (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data) -{ - bool embolden = font->x_strength || font->y_strength; - hb_outline_t outline; - - { // Need draw_session to be destructed before emboldening. - hb_draw_session_t draw_session (embolden ? hb_outline_recording_pen_get_funcs () : draw_funcs, - embolden ? &outline : draw_data, font->slant_xy); +static hb_bool_t +hb_ot_draw_glyph_or_fail (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data) +{ + hb_draw_session_t draw_session {draw_funcs, draw_data}; #ifndef HB_NO_VAR_COMPOSITES - if (!font->face->table.VARC->get_path (font, glyph, draw_session)) + if (font->face->table.VARC->get_path (font, glyph, draw_session)) return true; #endif - // Keep the following in synch with VARC::get_path_at() - if (!font->face->table.glyf->get_path (font, glyph, draw_session)) + // Keep the following in synch with VARC::get_path_at() + if (font->face->table.glyf->get_path (font, glyph, draw_session)) return true; #ifndef HB_NO_CFF - if (!font->face->table.cff2->get_path (font, glyph, draw_session)) - if (!font->face->table.cff1->get_path (font, glyph, draw_session)) + if (font->face->table.cff2->get_path (font, glyph, draw_session)) return true; + if (font->face->table.cff1->get_path (font, glyph, draw_session)) return true; #endif - {} - } - - if (embolden) - { - float x_shift = font->embolden_in_place ? 0 : (float) font->x_strength / 2; - float y_shift = (float) font->y_strength / 2; - if (font->x_scale < 0) x_shift = -x_shift; - if (font->y_scale < 0) y_shift = -y_shift; - outline.embolden (font->x_strength, font->y_strength, - x_shift, y_shift); - - outline.replay (draw_funcs, draw_data); - } + return false; } #endif #ifndef HB_NO_PAINT -static void -hb_ot_paint_glyph (hb_font_t *font, - void *font_data, - hb_codepoint_t glyph, - hb_paint_funcs_t *paint_funcs, void *paint_data, - unsigned int palette, - hb_color_t foreground, - void *user_data) +static hb_bool_t +hb_ot_paint_glyph_or_fail (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) { #ifndef HB_NO_COLOR - if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return; - if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return; + if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return true; + if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; #ifndef HB_NO_OT_FONT_BITMAP - if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return; - if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return; + if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; + if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; #endif #endif - - // Outline glyph - paint_funcs->push_clip_glyph (paint_data, glyph, font); - paint_funcs->color (paint_data, true, foreground); - paint_funcs->pop_clip (paint_data); + return false; } #endif @@ -642,11 +557,11 @@ #endif #ifndef HB_NO_DRAW - hb_font_funcs_set_draw_glyph_func (funcs, hb_ot_draw_glyph, nullptr, nullptr); + hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ot_draw_glyph_or_fail, nullptr, nullptr); #endif #ifndef HB_NO_PAINT - hb_font_funcs_set_paint_glyph_func (funcs, hb_ot_paint_glyph, nullptr, nullptr); + hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ot_paint_glyph_or_fail, nullptr, nullptr); #endif hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -359,7 +359,13 @@ return true; } - return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb); + // If there's no vmtx data, the phantom points from glyf table are not accurate, + // so we cannot take the next path. + bool is_vertical = T::tableTag == HB_OT_TAG_vmtx; + if (is_vertical && !has_data ()) + return false; + + return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb); #else return false; #endif diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -27,6 +27,7 @@ #ifndef HB_OT_KERN_TABLE_HH #define HB_OT_KERN_TABLE_HH +#include "hb-aat-layout-common.hh" #include "hb-aat-layout-kerx-table.hh" @@ -400,6 +401,7 @@ hb_blob_ptr_t table; AAT::kern_accelerator_data_t accel_data; + AAT::hb_aat_scratch_t scratch; }; protected: diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -182,7 +182,7 @@ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const { switch (u.format) { - case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set); + case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set); return; default:return; } } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh 2025-10-13 07:49:24.000000000 +0000 @@ -1850,7 +1850,7 @@ hb_sorted_vector_t glyph_and_klass; hb_set_t orig_klasses; - if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2 + if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) < get_population ()) { for (hb_codepoint_t g : glyph_set) @@ -1931,7 +1931,7 @@ bool intersects (const hb_set_t *glyphs) const { - if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2) + if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len)) { for (auto g : *glyphs) if (get_class (g)) @@ -2000,7 +2000,7 @@ } unsigned count = rangeRecord.len; - if (count > glyphs->get_population () * hb_bit_storage (count) * 8) + if (count > glyphs->get_population () * hb_bit_storage (count)) { for (auto g : *glyphs) { @@ -2548,11 +2548,13 @@ DEFINE_SIZE_STATIC (8); }; -#define REGION_CACHE_ITEM_CACHE_INVALID 2.f +#define REGION_CACHE_ITEM_CACHE_INVALID INT_MIN +#define REGION_CACHE_ITEM_MULTIPLIER (float (1 << ((sizeof (int) * 8) - 2))) +#define REGION_CACHE_ITEM_DIVISOR (1.f / float (1 << ((sizeof (int) * 8) - 2))) struct VarRegionList { - using cache_t = float; + using cache_t = hb_atomic_t; float evaluate (unsigned int region_index, const int *coords, unsigned int coord_len, @@ -2561,12 +2563,12 @@ if (unlikely (region_index >= regionCount)) return 0.; - float *cached_value = nullptr; + cache_t *cached_value = nullptr; if (cache) { cached_value = &(cache[region_index]); - if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)) - return *cached_value; + if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID) + return *cached_value * REGION_CACHE_ITEM_DIVISOR; } const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount); @@ -2587,7 +2589,7 @@ } if (cache) - *cached_value = v; + *cached_value = v * REGION_CACHE_ITEM_MULTIPLIER; return v; } @@ -2730,7 +2732,7 @@ struct SparseVarRegionList { - using cache_t = float; + using cache_t = hb_atomic_t; float evaluate (unsigned int region_index, const int *coords, unsigned int coord_len, @@ -2739,12 +2741,12 @@ if (unlikely (region_index >= regions.len)) return 0.; - float *cached_value = nullptr; + cache_t *cached_value = nullptr; if (cache) { cached_value = &(cache[region_index]); - if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)) - return *cached_value; + if (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID) + return *cached_value * REGION_CACHE_ITEM_DIVISOR; } const SparseVariationRegion ®ion = this+regions[region_index]; @@ -2752,7 +2754,7 @@ float v = region.evaluate (coords, coord_len); if (cache) - *cached_value = v; + *cached_value = v * REGION_CACHE_ITEM_MULTIPLIER; return v; } @@ -2861,8 +2863,13 @@ const hb_vector_t*>& rows) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); unsigned row_count = rows.length; + if (!row_count) { + // Nothing to serialize, will be empty. + return false; + } + + if (unlikely (!c->extend_min (this))) return_trace (false); itemCount = row_count; int min_threshold = has_long ? -65536 : -128; @@ -3187,10 +3194,10 @@ #ifdef HB_NO_VAR return nullptr; #endif - auto &r = this+regions; - unsigned count = r.regionCount; + unsigned count = (this+regions).regionCount; + if (!count) return nullptr; - float *cache = (float *) hb_malloc (sizeof (float) * count); + cache_t *cache = (cache_t *) hb_malloc (sizeof (float) * count); if (unlikely (!cache)) return nullptr; for (unsigned i = 0; i < count; i++) @@ -3440,7 +3447,7 @@ { using cache_t = SparseVarRegionList::cache_t; - cache_t *create_cache (hb_array_t static_cache = hb_array_t ()) const + cache_t *create_cache (hb_array_t static_cache = hb_array_t ()) const { #ifdef HB_NO_VAR return nullptr; @@ -3448,12 +3455,12 @@ auto &r = this+regions; unsigned count = r.regions.len; - float *cache; + cache_t *cache; if (count <= static_cache.length) cache = static_cache.arrayZ; else { - cache = (float *) hb_malloc (sizeof (float) * count); + cache = (cache_t *) hb_malloc (sizeof (float) * count); if (unlikely (!cache)) return nullptr; } @@ -3464,7 +3471,7 @@ } static void destroy_cache (cache_t *cache, - hb_array_t static_cache = hb_array_t ()) + hb_array_t static_cache = hb_array_t ()) { if (cache != static_cache.arrayZ) hb_free (cache); @@ -4777,12 +4784,12 @@ hb_position_t get_x_delta (hb_font_t *font, const ItemVariationStore &store, ItemVariationStore::cache_t *store_cache = nullptr) const - { return font->em_scalef_x (get_delta (font, store, store_cache)); } + { return !font->num_coords ? 0 : font->em_scalef_x (get_delta (font, store, store_cache)); } hb_position_t get_y_delta (hb_font_t *font, const ItemVariationStore &store, ItemVariationStore::cache_t *store_cache = nullptr) const - { return font->em_scalef_y (get_delta (font, store, store_cache)); } + { return !font->num_coords ? 0 : font->em_scalef_y (get_delta (font, store, store_cache)); } VariationDevice* copy (hb_serialize_context_t *c, const hb_hashmap_t> *layout_variation_idx_delta_map) const diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh 2025-10-13 07:49:24.000000000 +0000 @@ -737,7 +737,8 @@ hb_ot_apply_context_t (unsigned int table_index_, hb_font_t *font_, hb_buffer_t *buffer_, - hb_blob_t *table_blob_) : + hb_blob_t *table_blob_, + ItemVariationStore::cache_t *var_store_cache_ = nullptr) : table_index (table_index_), font (font_), face (font->face), buffer (buffer_), sanitizer (table_blob_), @@ -756,13 +757,7 @@ #endif ), var_store (gdef.get_var_store ()), - var_store_cache ( -#ifndef HB_NO_VAR - table_index == 1 && font->num_coords ? var_store.create_cache () : nullptr -#else - nullptr -#endif - ), + var_store_cache (var_store_cache_), direction (buffer_->props.direction), has_glyph_classes (gdef.has_glyph_classes ()) { @@ -770,13 +765,6 @@ buffer->collect_codepoints (digest); } - ~hb_ot_apply_context_t () - { -#ifndef HB_NO_VAR - ItemVariationStore::destroy_cache (var_store_cache); -#endif - } - void init_iters () { iter_input.init (this, false); @@ -4900,7 +4888,7 @@ this->lookup_count = table->get_lookup_count (); - this->accels = (hb_atomic_ptr_t *) hb_calloc (this->lookup_count, sizeof (*accels)); + this->accels = (hb_atomic_t *) hb_calloc (this->lookup_count, sizeof (*accels)); if (unlikely (!this->accels)) { this->lookup_count = 0; @@ -4948,7 +4936,7 @@ hb_blob_ptr_t table; unsigned int lookup_count; - hb_atomic_ptr_t *accels; + hb_atomic_t *accels; }; protected: diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc 2025-10-13 07:49:24.000000000 +0000 @@ -131,13 +131,15 @@ hb_font_t *font, hb_buffer_t *buffer) { - hb_blob_t *blob = font->face->table.kern.get_blob (); - const auto& kern = *font->face->table.kern; + auto &accel = *font->face->table.kern; + hb_blob_t *blob = accel.get_blob (); AAT::hb_aat_apply_context_t c (plan, font, buffer, blob); if (!buffer->message (font, "start table kern")) return; - kern.apply (&c); + c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set (); + accel.apply (&c); + accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set); (void) buffer->message (font, "end table kern"); } #endif @@ -2013,7 +2015,11 @@ { const unsigned int table_index = proxy.table_index; unsigned int i = 0; - OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob ()); + + auto *font_data = font->data.ot.get (); + auto *var_store_cache = font_data == HB_SHAPER_DATA_SUCCEEDED ? nullptr : (OT::ItemVariationStore::cache_t *) font_data; + + OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob (), var_store_cache); c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func); for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) @@ -2626,7 +2632,8 @@ * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer. * Alternate glyphs associated with the glyph id. * - * Fetches alternates of a glyph from a given GSUB lookup index. + * Fetches alternates of a glyph from a given GSUB lookup index. Note that for one-to-one GSUB + * glyph substitutions, this function fetches the substituted glyph. * * Return value: Total number of alternates found in the specific lookup index for the given glyph id. * diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh 2025-10-13 07:49:24.000000000 +0000 @@ -202,7 +202,8 @@ /* If GEN_CAT=FORMAT, top byte masks: */ UPROPS_MASK_Cf_ZWJ = 0x0100u, UPROPS_MASK_Cf_ZWNJ = 0x0200u, - UPROPS_MASK_Cf_VS = 0x0400u + UPROPS_MASK_Cf_VS = 0x0400u, + UPROPS_MASK_Cf_AAT_DELETED = 0x0800u }; HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t); @@ -386,6 +387,8 @@ static inline void _hb_ot_layout_reverse_graphemes (hb_buffer_t *buffer) { + // MONOTONE_GRAPHEMES was already applied and is taken care of by _hb_grapheme_group_func. + // So we just check for MONOTONE_CHARACTERS here. buffer->reverse_groups (_hb_grapheme_group_func, buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); } @@ -418,6 +421,18 @@ return; info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ; } +static inline bool +_hb_glyph_info_is_aat_deleted (const hb_glyph_info_t *info) +{ + return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_AAT_DELETED); +} +static inline void +_hb_glyph_info_set_aat_deleted (hb_glyph_info_t *info) +{ + _hb_glyph_info_set_general_category (info, HB_UNICODE_GENERAL_CATEGORY_FORMAT); + info->unicode_props() |= UPROPS_MASK_Cf_AAT_DELETED; + info->unicode_props() |= UPROPS_MASK_HIDDEN; +} /* lig_props: aka lig_id / lig_comp * diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -1104,6 +1104,24 @@ mathVariants.sanitize (c, this)); } + // https://github.com/harfbuzz/harfbuzz/issues/4653 + HB_INTERNAL bool is_bad_cambria (hb_font_t *font) const + { +#ifndef HB_NO_MATH + switch HB_CODEPOINT_ENCODE3 (font->face->table.MATH.get_blob ()->length, + get_constant (HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT, font), + get_constant (HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT, font)) + { + /* sha1sum:ab4a4fe054d23061f3c039493d6f665cfda2ecf5 cambria.ttc + * sha1sum:086855301bff644f9d8827b88491fcf73a6d4cb9 cambria.ttc + * sha1sum:b1e5a3feaca2ea3dfcf79ccb377de749ecf60343 cambria.ttc */ + case HB_CODEPOINT_ENCODE3 (25722, 2500, 3000): + return true; + } +#endif + return false; + } + hb_position_t get_constant (hb_ot_math_constant_t constant, hb_font_t *font) const { return (this+mathConstants).get_value (constant, font); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc 2025-10-13 07:49:24.000000000 +0000 @@ -87,6 +87,20 @@ hb_ot_math_get_constant (hb_font_t *font, hb_ot_math_constant_t constant) { + /* https://github.com/harfbuzz/harfbuzz/issues/4653 + * Cambria Math has incorrect value for displayOperatorMinHeight, and + * apparently Microsoft implementation swaps displayOperatorMinHeight and + * delimitedSubFormulaMinHeight, so we do the same if we detect Cambria Math + * with the swapped values. */ + if ((constant == HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT || + constant == HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT) && + font->face->table.MATH->is_bad_cambria (font)) + { + if (constant == HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT) + constant = HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT; + else + constant = HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT; + } return font->face->table.MATH->get_constant(constant, font); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -290,7 +290,7 @@ const Array16Of *glyphNameIndex = nullptr; hb_vector_t index_to_offset; const uint8_t *pool = nullptr; - hb_atomic_ptr_t gids_sorted_by_name; + mutable hb_atomic_t gids_sorted_by_name; }; bool has_data () const { return version.to_int (); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc 2025-10-13 07:49:24.000000000 +0000 @@ -427,8 +427,13 @@ /* Find mark glyphs */ unsigned int j; for (j = i + 1; j < end; j++) + { + if (_hb_glyph_info_is_hidden (&info[j]) || + _hb_glyph_info_is_default_ignorable (&info[j])) + continue; if (!_hb_glyph_info_is_unicode_mark (&info[j])) break; + } position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing); @@ -455,7 +460,9 @@ unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 1; i < count; i++) - if (likely (!_hb_glyph_info_is_unicode_mark (&info[i]))) { + if (likely (!_hb_glyph_info_is_unicode_mark (&info[i]) && + !_hb_glyph_info_is_hidden (&info[i]) && + !_hb_glyph_info_is_default_ignorable (&info[i]))) { position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing); start = i; } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc 2025-10-13 07:49:24.000000000 +0000 @@ -46,6 +46,7 @@ #include "hb-set.hh" #include "hb-aat-layout.hh" +#include "hb-ot-layout-gdef-table.hh" #include "hb-ot-stat-table.hh" @@ -84,6 +85,7 @@ props (props), map (face, props) #ifndef HB_NO_AAT_SHAPE + , aat_map (face, props) , apply_morx (_hb_apply_morx (face, props)) #endif { @@ -106,6 +108,10 @@ plan.props = props; plan.shaper = shaper; map.compile (plan.map, key); +#ifndef HB_NO_AAT_SHAPE + if (apply_morx) + aat_map.compile (plan.aat_map); +#endif #ifndef HB_NO_OT_SHAPE_FRACTIONS plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c')); @@ -205,6 +211,14 @@ https://github.com/harfbuzz/harfbuzz/issues/2967. */ if (plan.apply_morx) plan.adjust_mark_positioning_when_zeroing = false; + + /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */ +#ifndef HB_NO_STYLE + plan.apply_trak = hb_aat_layout_has_tracking (face) && face->table.STAT->has_data (); +#else + plan.apply_trak = false; +#endif + #endif } @@ -269,6 +283,11 @@ #endif else if (this->apply_fallback_kern) _hb_ot_shape_fallback_kern (this, font, buffer); + +#ifndef HB_NO_AAT_SHAPE + if (this->apply_trak) + hb_aat_layout_track (this, font, buffer); +#endif } @@ -405,17 +424,26 @@ * shaper font data */ -struct hb_ot_font_data_t {}; +struct hb_ot_font_data_t { + OT::ItemVariationStore::cache_t unused; // Just for alignment +}; hb_ot_font_data_t * -_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED) +_hb_ot_shaper_font_data_create (hb_font_t *font) { - return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; + if (!font->num_coords) + return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; + + const OT::ItemVariationStore &var_store = font->face->table.GDEF->table->get_var_store (); + auto *cache = (hb_ot_font_data_t *) var_store.create_cache (); + return cache ? cache : (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data HB_UNUSED) +_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data) { + if (data == HB_SHAPER_DATA_SUCCEEDED) return; + OT::ItemVariationStore::destroy_cache ((OT::ItemVariationStore::cache_t *) data); } @@ -551,7 +579,7 @@ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII)) return; - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) + if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level)) foreach_grapheme (buffer, start, end) buffer->merge_clusters (start, end); else @@ -609,7 +637,7 @@ * Ogham fonts are supposed to be implemented BTT or not. Need to research that * first. */ if ((HB_DIRECTION_IS_HORIZONTAL (direction) && - direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) || + direction != horiz_dir && HB_DIRECTION_IS_VALID (horiz_dir)) || (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) { @@ -1109,10 +1137,6 @@ /* Finish off. Has to follow a certain order. */ hb_ot_layout_position_finish_advances (c->font, c->buffer); hb_ot_zero_width_default_ignorables (c->buffer); -#ifndef HB_NO_AAT_SHAPE - if (c->plan->apply_morx) - hb_aat_layout_zero_width_deleted_glyphs (c->buffer); -#endif hb_ot_layout_position_finish_offsets (c->font, c->buffer); /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh 2025-10-13 07:49:24.000000000 +0000 @@ -66,6 +66,7 @@ hb_segment_properties_t props; const struct hb_ot_shaper_t *shaper; hb_ot_map_t map; + hb_aat_map_t aat_map; const void *data; #ifndef HB_NO_OT_SHAPE_FRACTIONS hb_mask_t frac_mask, numr_mask, dnom_mask; @@ -108,9 +109,11 @@ #ifndef HB_NO_AAT_SHAPE bool apply_kerx : 1; bool apply_morx : 1; + bool apply_trak : 1; #else static constexpr bool apply_kerx = false; static constexpr bool apply_morx = false; + static constexpr bool apply_trak = false; #endif void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const @@ -141,6 +144,7 @@ hb_segment_properties_t props; hb_ot_map_builder_t map; #ifndef HB_NO_AAT_SHAPE + hb_aat_map_builder_t aat_map; bool apply_morx : 1; #else static constexpr bool apply_morx = false; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc 2025-10-13 07:49:24.000000000 +0000 @@ -260,7 +260,7 @@ * mask_array[NONE] == 0. */ hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1]; - hb_atomic_ptr_t fallback_plan; + mutable hb_atomic_t fallback_plan; unsigned int do_fallback : 1; unsigned int has_stch : 1; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc 2025-10-13 07:49:24.000000000 +0000 @@ -298,8 +298,7 @@ end = start + 2; if (unlikely (!buffer->successful)) break; - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) - buffer->merge_out_clusters (start, end); + buffer->merge_out_clusters (start, end); continue; } } @@ -372,8 +371,7 @@ if (i < end) info[i++].hangul_shaping_feature() = TJMO; - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) - buffer->merge_out_clusters (start, end); + buffer->merge_out_clusters (start, end); continue; } else if ((!tindex && buffer->idx + 1 < count && isT (buffer->cur(+1).codepoint))) diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic.cc 2025-10-13 07:49:24.000000000 +0000 @@ -301,7 +301,7 @@ #else static constexpr bool uniscribe_bug_compatible = false; #endif - mutable hb_atomic_int_t virama_glyph; + mutable hb_atomic_t virama_glyph; hb_indic_would_substitute_feature_t rphf; hb_indic_would_substitute_feature_t pref; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc 2025-10-13 07:49:24.000000000 +0000 @@ -360,7 +360,7 @@ { /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the * previous cluster. */ - if (start && buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) + if (start) buffer->merge_out_clusters (start - 1, end); } } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc 2025-10-13 07:49:24.000000000 +0000 @@ -326,7 +326,7 @@ hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len); - static hb_atomic_int_t last_tag_idx; /* Poor man's cache. */ + static hb_atomic_t last_tag_idx = 0; /* Poor man's cache. */ unsigned tag_idx = last_tag_idx; if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) || diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh 2025-10-13 07:49:24.000000000 +0000 @@ -53,10 +53,6 @@ contour_point_vector_t deltas; hb_vector_t shared_indices; hb_vector_t private_indices; - - // VARC - hb_vector_t axisIndices; - hb_vector_t axisValues; }; namespace OT { @@ -594,9 +590,9 @@ /* If sanitize failed, set glyphCount to 0. */ glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0; - /* For shared tuples that only have one axis active, shared the index of - * that axis as a cache. This will speed up caclulate_scalar() a lot - * for fonts with lots of axes and many "monovar" tuples. */ + /* For shared tuples that only have one or two axes active, shared the index + * of that axis as a cache. This will speed up caclulate_scalar() a lot + * for fonts with lots of axes and many "monovar" or "duovar" tuples. */ hb_array_t shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount); unsigned count = table->sharedTupleCount; if (unlikely (!shared_tuple_active_idx.resize (count, false))) return; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc 2025-10-13 07:49:24.000000000 +0000 @@ -117,7 +117,7 @@ * in the specified face. * * Since: 1.4.2 - * Deprecated: 2.2.0 - use hb_ot_var_find_axis_info() instead + * Deprecated: 2.2.0: use hb_ot_var_find_axis_info() instead **/ hb_bool_t hb_ot_var_find_axis (hb_face_t *face, diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-outline.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-outline.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-outline.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-outline.cc 2025-10-13 07:49:24.000000000 +0000 @@ -84,6 +84,12 @@ } } +void hb_outline_t::slant (float slant_xy) +{ + for (auto &p : points) + p.x += slant_xy * p.y; +} + float hb_outline_t::control_area () const { float a = 0; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-outline.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-outline.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-outline.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-outline.hh 2025-10-13 07:49:24.000000000 +0000 @@ -69,6 +69,7 @@ HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const; HB_INTERNAL float control_area () const; + HB_INTERNAL void slant (float slant_xy); HB_INTERNAL void embolden (float x_strength, float y_strength, float x_shift, float y_shift); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.cc 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.cc 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,207 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#ifndef HB_NO_PAINT + +#include "hb-paint-bounded.hh" + +#include "hb-machinery.hh" + + +/* + * This file implements boundedness computation of COLRv1 fonts as described in: + * + * https://learn.microsoft.com/en-us/typography/opentype/spec/colr#glyph-metrics-and-boundedness + */ + +static void +hb_paint_bounded_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->push_clip (); +} + +static void +hb_paint_bounded_push_clip_rectangle (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + float xmin, float ymin, float xmax, float ymax, + void *user_data) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->push_clip (); +} + +static void +hb_paint_bounded_pop_clip (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->pop_clip (); +} + +static void +hb_paint_bounded_push_group (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->push_group (); +} + +static void +hb_paint_bounded_pop_group (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + hb_paint_composite_mode_t mode, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->pop_group (mode); +} + +static hb_bool_t +hb_paint_bounded_paint_image (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + hb_blob_t *blob HB_UNUSED, + unsigned int width HB_UNUSED, + unsigned int height HB_UNUSED, + hb_tag_t format HB_UNUSED, + float slant HB_UNUSED, + hb_glyph_extents_t *glyph_extents, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->push_clip (); + c->paint (); + c->pop_clip (); + + return true; +} + +static void +hb_paint_bounded_paint_color (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + hb_bool_t use_foreground HB_UNUSED, + hb_color_t color HB_UNUSED, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->paint (); +} + +static void +hb_paint_bounded_paint_linear_gradient (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line HB_UNUSED, + float x0 HB_UNUSED, float y0 HB_UNUSED, + float x1 HB_UNUSED, float y1 HB_UNUSED, + float x2 HB_UNUSED, float y2 HB_UNUSED, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->paint (); +} + +static void +hb_paint_bounded_paint_radial_gradient (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line HB_UNUSED, + float x0 HB_UNUSED, float y0 HB_UNUSED, float r0 HB_UNUSED, + float x1 HB_UNUSED, float y1 HB_UNUSED, float r1 HB_UNUSED, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->paint (); +} + +static void +hb_paint_bounded_paint_sweep_gradient (hb_paint_funcs_t *funcs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line HB_UNUSED, + float cx HB_UNUSED, float cy HB_UNUSED, + float start_angle HB_UNUSED, + float end_angle HB_UNUSED, + void *user_data HB_UNUSED) +{ + hb_paint_bounded_context_t *c = (hb_paint_bounded_context_t *) paint_data; + + c->paint (); +} + +static inline void free_static_paint_bounded_funcs (); + +static struct hb_paint_bounded_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t +{ + static hb_paint_funcs_t *create () + { + hb_paint_funcs_t *funcs = hb_paint_funcs_create (); + + hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_paint_bounded_push_clip_glyph, nullptr, nullptr); + hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_paint_bounded_push_clip_rectangle, nullptr, nullptr); + hb_paint_funcs_set_pop_clip_func (funcs, hb_paint_bounded_pop_clip, nullptr, nullptr); + hb_paint_funcs_set_push_group_func (funcs, hb_paint_bounded_push_group, nullptr, nullptr); + hb_paint_funcs_set_pop_group_func (funcs, hb_paint_bounded_pop_group, nullptr, nullptr); + hb_paint_funcs_set_color_func (funcs, hb_paint_bounded_paint_color, nullptr, nullptr); + hb_paint_funcs_set_image_func (funcs, hb_paint_bounded_paint_image, nullptr, nullptr); + hb_paint_funcs_set_linear_gradient_func (funcs, hb_paint_bounded_paint_linear_gradient, nullptr, nullptr); + hb_paint_funcs_set_radial_gradient_func (funcs, hb_paint_bounded_paint_radial_gradient, nullptr, nullptr); + hb_paint_funcs_set_sweep_gradient_func (funcs, hb_paint_bounded_paint_sweep_gradient, nullptr, nullptr); + + hb_paint_funcs_make_immutable (funcs); + + hb_atexit (free_static_paint_bounded_funcs); + + return funcs; + } +} static_paint_bounded_funcs; + +static inline +void free_static_paint_bounded_funcs () +{ + static_paint_bounded_funcs.free_instance (); +} + +hb_paint_funcs_t * +hb_paint_bounded_get_funcs () +{ + return static_paint_bounded_funcs.get_unconst (); +} + + +#endif diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.hh 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-bounded.hh 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,117 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_PAINT_BOUNDED_HH +#define HB_PAINT_BOUNDED_HH + +#include "hb.hh" +#include "hb-paint.h" + +#include "hb-geometry.hh" + + +typedef struct hb_paint_bounded_context_t hb_paint_bounded_context_t; + +struct hb_paint_bounded_context_t +{ + void clear () + { + clips = 0; + bounded = true; + groups.clear (); + } + + hb_paint_bounded_context_t () + { + clear (); + } + + bool is_bounded () + { + return bounded; + } + + void push_clip () + { + clips++; + } + + void pop_clip () + { + if (clips == 0) return; + clips--; + } + + void push_group () + { + groups.push (bounded); + bounded = true; + } + + void pop_group (hb_paint_composite_mode_t mode) + { + const bool src_bounded = bounded; + bounded = groups.pop (); + bool &backdrop_bounded = bounded; + + // https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite + switch ((int) mode) + { + case HB_PAINT_COMPOSITE_MODE_CLEAR: + backdrop_bounded = true; + break; + case HB_PAINT_COMPOSITE_MODE_SRC: + case HB_PAINT_COMPOSITE_MODE_SRC_OUT: + backdrop_bounded = src_bounded; + break; + case HB_PAINT_COMPOSITE_MODE_DEST: + case HB_PAINT_COMPOSITE_MODE_DEST_OUT: + break; + case HB_PAINT_COMPOSITE_MODE_SRC_IN: + case HB_PAINT_COMPOSITE_MODE_DEST_IN: + backdrop_bounded = backdrop_bounded && src_bounded; + break; + default: + backdrop_bounded = backdrop_bounded || src_bounded; + break; + } + } + + void paint () + { + if (!clips) + bounded = false; + } + + protected: + bool bounded; // true if current drawing bounded + unsigned clips; // number of active clips + hb_vector_t groups; // true if group bounded +}; + +HB_INTERNAL hb_paint_funcs_t * +hb_paint_bounded_get_funcs (); + + +#endif /* HB_PAINT_BOUNDED_HH */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc 2025-10-13 07:49:24.000000000 +0000 @@ -28,14 +28,13 @@ #include "hb-paint-extents.hh" -#include "hb-draw.h" +#include "hb-draw.hh" #include "hb-machinery.hh" /* - * This file implements bounds-extraction as well as boundedness - * computation of COLRv1 fonts as described in: + * This file implements bounds-extraction computation of COLRv1 fonts as described in: * * https://learn.microsoft.com/en-us/typography/opentype/spec/colr#glyph-metrics-and-boundedness */ @@ -64,93 +63,6 @@ } static void -hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, - void *data, - hb_draw_state_t *st, - float to_x, float to_y, - void *user_data HB_UNUSED) -{ - hb_extents_t *extents = (hb_extents_t *) data; - - extents->add_point (to_x, to_y); -} - -static void -hb_draw_extents_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, - void *data, - hb_draw_state_t *st, - float to_x, float to_y, - void *user_data HB_UNUSED) -{ - hb_extents_t *extents = (hb_extents_t *) data; - - extents->add_point (to_x, to_y); -} - -static void -hb_draw_extents_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, - void *data, - hb_draw_state_t *st, - float control_x, float control_y, - float to_x, float to_y, - void *user_data HB_UNUSED) -{ - hb_extents_t *extents = (hb_extents_t *) data; - - extents->add_point (control_x, control_y); - extents->add_point (to_x, to_y); -} - -static void -hb_draw_extents_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, - void *data, - hb_draw_state_t *st, - float control1_x, float control1_y, - float control2_x, float control2_y, - float to_x, float to_y, - void *user_data HB_UNUSED) -{ - hb_extents_t *extents = (hb_extents_t *) data; - - extents->add_point (control1_x, control1_y); - extents->add_point (control2_x, control2_y); - extents->add_point (to_x, to_y); -} - -static inline void free_static_draw_extents_funcs (); - -static struct hb_draw_extents_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t -{ - static hb_draw_funcs_t *create () - { - hb_draw_funcs_t *funcs = hb_draw_funcs_create (); - - hb_draw_funcs_set_move_to_func (funcs, hb_draw_extents_move_to, nullptr, nullptr); - hb_draw_funcs_set_line_to_func (funcs, hb_draw_extents_line_to, nullptr, nullptr); - hb_draw_funcs_set_quadratic_to_func (funcs, hb_draw_extents_quadratic_to, nullptr, nullptr); - hb_draw_funcs_set_cubic_to_func (funcs, hb_draw_extents_cubic_to, nullptr, nullptr); - - hb_draw_funcs_make_immutable (funcs); - - hb_atexit (free_static_draw_extents_funcs); - - return funcs; - } -} static_draw_extents_funcs; - -static inline -void free_static_draw_extents_funcs () -{ - static_draw_extents_funcs.free_instance (); -} - -static hb_draw_funcs_t * -hb_draw_extents_get_funcs () -{ - return static_draw_extents_funcs.get_unconst (); -} - -static void hb_paint_extents_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED, void *paint_data, hb_codepoint_t glyph, @@ -221,6 +133,9 @@ { hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data; + if (!glyph_extents) + return false; // Happens with SVG images. + hb_extents_t extents = {(float) glyph_extents->x_bearing, (float) glyph_extents->y_bearing + glyph_extents->height, (float) glyph_extents->x_bearing + glyph_extents->width, diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh 2025-10-13 07:49:24.000000000 +0000 @@ -35,13 +35,22 @@ struct hb_paint_extents_context_t { - hb_paint_extents_context_t () + void clear () { + transforms.clear (); + clips.clear (); + groups.clear (); + transforms.push (hb_transform_t{}); clips.push (hb_bounds_t{hb_bounds_t::UNBOUNDED}); groups.push (hb_bounds_t{hb_bounds_t::EMPTY}); } + hb_paint_extents_context_t () + { + clear (); + } + hb_extents_t get_extents () { return groups.tail().extents; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.cc 2025-10-13 07:49:24.000000000 +0000 @@ -87,7 +87,7 @@ unsigned int width, unsigned int height, hb_tag_t format, - float slant_xy, + float slant_xy_deprecated, hb_glyph_extents_t *extents, void *user_data) { return false; } @@ -465,6 +465,42 @@ } /** + * hb_paint_push_font_transform: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * @font: a font + * + * Push the transform reflecting the font's scale and slant + * settings onto the paint functions. + * + * Since: 11.0.0 + */ +void +hb_paint_push_font_transform (hb_paint_funcs_t *funcs, void *paint_data, + const hb_font_t *font) +{ + funcs->push_font_transform (paint_data, font); +} + +/** + * hb_paint_push_inverse_font_transform: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * @font: a font + * + * Push the inverse of the transform reflecting the font's + * scale and slant settings onto the paint functions. + * + * Since: 11.0.0 + */ +void +hb_paint_push_inverse_font_transform (hb_paint_funcs_t *funcs, void *paint_data, + const hb_font_t *font) +{ + funcs->push_inverse_font_transform (paint_data, font); +} + +/** * hb_paint_pop_transform: * @funcs: paint functions * @paint_data: associated data passed by the caller @@ -579,7 +615,7 @@ * @width: width of the raster image in pixels, or 0 * @height: height of the raster image in pixels, or 0 * @format: the image format as a tag - * @slant: the synthetic slant ratio to be applied to the image during rendering + * @slant: Deprecated. set to 0.0 * @extents: (nullable): the extents of the glyph * * Perform a "image" paint operation. @@ -592,10 +628,10 @@ unsigned int width, unsigned int height, hb_tag_t format, - float slant, + HB_UNUSED float slant, hb_glyph_extents_t *extents) { - funcs->image (paint_data, image, width, height, format, slant, extents); + funcs->image (paint_data, image, width, height, format, 0.f, extents); } /** @@ -646,7 +682,7 @@ float x0, float y0, float r0, float x1, float y1, float r1) { - funcs->radial_gradient (paint_data, color_line, x0, y0, r0, y1, x1, r1); + funcs->radial_gradient (paint_data, color_line, x0, y0, r0, x1, y1, r1); } /** diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.h 2025-10-13 07:49:24.000000000 +0000 @@ -167,8 +167,10 @@ * A virtual method for the #hb_paint_funcs_t to clip * subsequent paint calls to the outline of a glyph. * - * The coordinates of the glyph outline are interpreted according - * to the current transform. + * The coordinates of the glyph outline are expected in the + * current @font scale (ie. the results of calling + * hb_font_draw_glyph() with @font). The outline is + * transformed by the current transform. * * This clip is applied in addition to the current clip, * and remains in effect until a matching call to @@ -281,7 +283,7 @@ * @width: width of the raster image in pixels, or 0 * @height: height of the raster image in pixels, or 0 * @format: the image format as a tag - * @slant: the synthetic slant ratio to be applied to the image during rendering + * @slant: Deprecated. Always set to 0.0. * @extents: (nullable): glyph extents for desired rendering * @user_data: User data pointer passed to hb_paint_funcs_set_image_func() * @@ -957,6 +959,14 @@ float dx, float dy); HB_EXTERN void +hb_paint_push_font_transform (hb_paint_funcs_t *funcs, void *paint_data, + const hb_font_t *font); + +HB_EXTERN void +hb_paint_push_inverse_font_transform (hb_paint_funcs_t *funcs, void *paint_data, + const hb_font_t *font); + +HB_EXTERN void hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data); HB_EXTERN hb_bool_t diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-paint.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-paint.hh 2025-10-13 07:49:24.000000000 +0000 @@ -157,27 +157,29 @@ /* Internal specializations. */ - void push_root_transform (void *paint_data, + void push_font_transform (void *paint_data, const hb_font_t *font) { float upem = font->face->get_upem (); int xscale = font->x_scale, yscale = font->y_scale; - float slant = font->slant_xy; push_transform (paint_data, - xscale/upem, 0, slant * yscale/upem, yscale/upem, 0, 0); + xscale/upem, 0, + 0, yscale/upem, + 0, 0); } - void push_inverse_root_transform (void *paint_data, - hb_font_t *font) + void push_inverse_font_transform (void *paint_data, + const hb_font_t *font) { float upem = font->face->get_upem (); int xscale = font->x_scale ? font->x_scale : upem; int yscale = font->y_scale ? font->y_scale : upem; - float slant = font->slant_xy; push_transform (paint_data, - upem/xscale, 0, -slant * upem/xscale, upem/yscale, 0, 0); + upem/xscale, 0, + 0, upem/yscale, + 0, 0); } HB_NODISCARD diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-script-list.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-script-list.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-script-list.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-script-list.h 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,484 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) +#error "Include instead." +#endif + +#ifndef HB_SCRIPT_LIST_H +#define HB_SCRIPT_LIST_H + +/* This file belongs to the middle of hb-common.h. + * The reason it has been surgically extracted is because + * FreeType imports types and enums from hb-common.h, + * and since this enum is large and growing, we want to + * make it easy to just copy the file over to FreeType. + * https://github.com/harfbuzz/harfbuzz/issues/5271 + */ + +/* Dummy lines to make our checks happy. */ +#if 0 +#include "hb-common.h" +HB_BEGIN_DECLS +HB_END_DECLS +#endif + + +/** + * hb_script_t: + * @HB_SCRIPT_COMMON: `Zyyy` + * @HB_SCRIPT_INHERITED: `Zinh` + * @HB_SCRIPT_UNKNOWN: `Zzzz` + * @HB_SCRIPT_ARABIC: `Arab` + * @HB_SCRIPT_ARMENIAN: `Armn` + * @HB_SCRIPT_BENGALI: `Beng` + * @HB_SCRIPT_CYRILLIC: `Cyrl` + * @HB_SCRIPT_DEVANAGARI: `Deva` + * @HB_SCRIPT_GEORGIAN: `Geor` + * @HB_SCRIPT_GREEK: `Grek` + * @HB_SCRIPT_GUJARATI: `Gujr` + * @HB_SCRIPT_GURMUKHI: `Guru` + * @HB_SCRIPT_HANGUL: `Hang` + * @HB_SCRIPT_HAN: `Hani` + * @HB_SCRIPT_HEBREW: `Hebr` + * @HB_SCRIPT_HIRAGANA: `Hira` + * @HB_SCRIPT_KANNADA: `Knda` + * @HB_SCRIPT_KATAKANA: `Kana` + * @HB_SCRIPT_LAO: `Laoo` + * @HB_SCRIPT_LATIN: `Latn` + * @HB_SCRIPT_MALAYALAM: `Mlym` + * @HB_SCRIPT_ORIYA: `Orya` + * @HB_SCRIPT_TAMIL: `Taml` + * @HB_SCRIPT_TELUGU: `Telu` + * @HB_SCRIPT_THAI: `Thai` + * @HB_SCRIPT_TIBETAN: `Tibt` + * @HB_SCRIPT_BOPOMOFO: `Bopo` + * @HB_SCRIPT_BRAILLE: `Brai` + * @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans` + * @HB_SCRIPT_CHEROKEE: `Cher` + * @HB_SCRIPT_ETHIOPIC: `Ethi` + * @HB_SCRIPT_KHMER: `Khmr` + * @HB_SCRIPT_MONGOLIAN: `Mong` + * @HB_SCRIPT_MYANMAR: `Mymr` + * @HB_SCRIPT_OGHAM: `Ogam` + * @HB_SCRIPT_RUNIC: `Runr` + * @HB_SCRIPT_SINHALA: `Sinh` + * @HB_SCRIPT_SYRIAC: `Syrc` + * @HB_SCRIPT_THAANA: `Thaa` + * @HB_SCRIPT_YI: `Yiii` + * @HB_SCRIPT_DESERET: `Dsrt` + * @HB_SCRIPT_GOTHIC: `Goth` + * @HB_SCRIPT_OLD_ITALIC: `Ital` + * @HB_SCRIPT_BUHID: `Buhd` + * @HB_SCRIPT_HANUNOO: `Hano` + * @HB_SCRIPT_TAGALOG: `Tglg` + * @HB_SCRIPT_TAGBANWA: `Tagb` + * @HB_SCRIPT_CYPRIOT: `Cprt` + * @HB_SCRIPT_LIMBU: `Limb` + * @HB_SCRIPT_LINEAR_B: `Linb` + * @HB_SCRIPT_OSMANYA: `Osma` + * @HB_SCRIPT_SHAVIAN: `Shaw` + * @HB_SCRIPT_TAI_LE: `Tale` + * @HB_SCRIPT_UGARITIC: `Ugar` + * @HB_SCRIPT_BUGINESE: `Bugi` + * @HB_SCRIPT_COPTIC: `Copt` + * @HB_SCRIPT_GLAGOLITIC: `Glag` + * @HB_SCRIPT_KHAROSHTHI: `Khar` + * @HB_SCRIPT_NEW_TAI_LUE: `Talu` + * @HB_SCRIPT_OLD_PERSIAN: `Xpeo` + * @HB_SCRIPT_SYLOTI_NAGRI: `Sylo` + * @HB_SCRIPT_TIFINAGH: `Tfng` + * @HB_SCRIPT_BALINESE: `Bali` + * @HB_SCRIPT_CUNEIFORM: `Xsux` + * @HB_SCRIPT_NKO: `Nkoo` + * @HB_SCRIPT_PHAGS_PA: `Phag` + * @HB_SCRIPT_PHOENICIAN: `Phnx` + * @HB_SCRIPT_CARIAN: `Cari` + * @HB_SCRIPT_CHAM: `Cham` + * @HB_SCRIPT_KAYAH_LI: `Kali` + * @HB_SCRIPT_LEPCHA: `Lepc` + * @HB_SCRIPT_LYCIAN: `Lyci` + * @HB_SCRIPT_LYDIAN: `Lydi` + * @HB_SCRIPT_OL_CHIKI: `Olck` + * @HB_SCRIPT_REJANG: `Rjng` + * @HB_SCRIPT_SAURASHTRA: `Saur` + * @HB_SCRIPT_SUNDANESE: `Sund` + * @HB_SCRIPT_VAI: `Vaii` + * @HB_SCRIPT_AVESTAN: `Avst` + * @HB_SCRIPT_BAMUM: `Bamu` + * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp` + * @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi` + * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli` + * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti` + * @HB_SCRIPT_JAVANESE: `Java` + * @HB_SCRIPT_KAITHI: `Kthi` + * @HB_SCRIPT_LISU: `Lisu` + * @HB_SCRIPT_MEETEI_MAYEK: `Mtei` + * @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb` + * @HB_SCRIPT_OLD_TURKIC: `Orkh` + * @HB_SCRIPT_SAMARITAN: `Samr` + * @HB_SCRIPT_TAI_THAM: `Lana` + * @HB_SCRIPT_TAI_VIET: `Tavt` + * @HB_SCRIPT_BATAK: `Batk` + * @HB_SCRIPT_BRAHMI: `Brah` + * @HB_SCRIPT_MANDAIC: `Mand` + * @HB_SCRIPT_CHAKMA: `Cakm` + * @HB_SCRIPT_MEROITIC_CURSIVE: `Merc` + * @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero` + * @HB_SCRIPT_MIAO: `Plrd` + * @HB_SCRIPT_SHARADA: `Shrd` + * @HB_SCRIPT_SORA_SOMPENG: `Sora` + * @HB_SCRIPT_TAKRI: `Takr` + * @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30 + * @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30 + * @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30 + * @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30 + * @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30 + * @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30 + * @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30 + * @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30 + * @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30 + * @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30 + * @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30 + * @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30 + * @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30 + * @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30 + * @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30 + * @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30 + * @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30 + * @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30 + * @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30 + * @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30 + * @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30 + * @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30 + * @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30 + * @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30 + * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30 + * @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30 + * @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30 + * @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30 + * @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30 + * @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0 + * @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0 + * @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0 + * @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0 + * @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0 + * @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0 + * @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0 + * @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0 + * @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0 + * @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0 + * @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0 + * @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0 + * @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0 + * @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0 + * @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0 + * @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0 + * @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0 + * @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0 + * @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0 + * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0 + * @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0 + * @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7 + * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7 + * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7 + * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7 + * @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0 + * @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0 + * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0 + * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0 + * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0 + * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0 + * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0 + * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0 + * @HB_SCRIPT_GARAY: `Gara`, Since: 10.0.0 + * @HB_SCRIPT_GURUNG_KHEMA: `Gukh`, Since: 10.0.0 + * @HB_SCRIPT_KIRAT_RAI: `Krai`, Since: 10.0.0 + * @HB_SCRIPT_OL_ONAL: `Onao`, Since: 10.0.0 + * @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0 + * @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0 + * @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0 + * @HB_SCRIPT_INVALID: No script set + * + * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding + * to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/). + * + * See also the Script (sc) property of the Unicode Character Database. + * + **/ + +/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */ +typedef enum +{ + HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/ + HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/ + HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/ + + HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/ + HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/ + HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/ + HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/ + HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/ + HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/ + HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/ + HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/ + HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/ + HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/ + HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/ + HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/ + HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/ + HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/ + HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/ + HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/ + HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/ + HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/ + HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/ + HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/ + HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/ + HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/ + + HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/ + + HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/ + HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/ + HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/ + HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/ + HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/ + HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/ + HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/ + HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/ + HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/ + HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/ + HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/ + HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/ + HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/ + HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/ + + HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/ + HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/ + HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/ + + HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/ + HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/ + HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/ + HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/ + + HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/ + HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/ + HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/ + HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/ + HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/ + HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/ + HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/ + + HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/ + HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/ + HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/ + HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/ + HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/ + HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/ + HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/ + HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/ + + HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/ + HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/ + HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/ + HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/ + HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/ + + HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/ + HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/ + HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/ + HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/ + HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/ + HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/ + HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/ + HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/ + HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/ + HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/ + HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/ + + HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/ + HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/ + HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/ + HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/ + HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/ + HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/ + HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/ + HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/ + HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/ + HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/ + HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/ + HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/ + HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/ + HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/ + HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/ + + HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/ + HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/ + HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/ + + HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/ + HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/ + HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/ + HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/ + HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/ + HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/ + HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/ + + /* + * Since: 0.9.30 + */ + HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/ + HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/ + HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/ + HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/ + HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/ + HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/ + HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/ + HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/ + HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/ + HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/ + HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/ + HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/ + HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/ + HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/ + HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/ + HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/ + HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/ + HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/ + HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/ + HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/ + HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/ + HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/ + HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/ + + HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/ + HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/ + HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/ + HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/ + HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/ + HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/ + + /* + * Since 1.3.0 + */ + HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/ + HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/ + HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/ + HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/ + HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/ + HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/ + + /* + * Since 1.6.0 + */ + HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/ + HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/ + HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/ + HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/ + + /* + * Since 1.8.0 + */ + HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/ + HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/ + HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/ + HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/ + HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/ + HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/ + HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/ + + /* + * Since 2.4.0 + */ + HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/ + HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/ + HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/ + HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/ + + /* + * Since 2.6.7 + */ + HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/ + HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/ + HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/ + HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/ + + /* + * Since 3.0.0 + */ + HB_SCRIPT_CYPRO_MINOAN = HB_TAG ('C','p','m','n'), /*14.0*/ + HB_SCRIPT_OLD_UYGHUR = HB_TAG ('O','u','g','r'), /*14.0*/ + HB_SCRIPT_TANGSA = HB_TAG ('T','n','s','a'), /*14.0*/ + HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/ + HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/ + + /* + * Since 3.4.0 + */ + HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'), + + /* + * Since 5.2.0 + */ + HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/ + HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/ + + /* + * Since 10.0.0 + */ + HB_SCRIPT_GARAY = HB_TAG ('G','a','r','a'), /*16.0*/ + HB_SCRIPT_GURUNG_KHEMA = HB_TAG ('G','u','k','h'), /*16.0*/ + HB_SCRIPT_KIRAT_RAI = HB_TAG ('K','r','a','i'), /*16.0*/ + HB_SCRIPT_OL_ONAL = HB_TAG ('O','n','a','o'), /*16.0*/ + HB_SCRIPT_SUNUWAR = HB_TAG ('S','u','n','u'), /*16.0*/ + HB_SCRIPT_TODHRI = HB_TAG ('T','o','d','r'), /*16.0*/ + HB_SCRIPT_TULU_TIGALARI = HB_TAG ('T','u','t','g'), /*16.0*/ + + /* No script set. */ + HB_SCRIPT_INVALID = HB_TAG_NONE, + + /*< private >*/ + + /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t + * without risking undefined behavior. We have two, for historical reasons. + * HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed + * to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well. + * + * See this thread for technicalities: + * + * https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html + */ + _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/ + _HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/ + +} hb_script_t; + + +#endif /* HB_SCRIPT_LIST_H */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-set-digest.hh 2025-10-13 07:49:24.000000000 +0000 @@ -31,11 +31,10 @@ #include "hb-machinery.hh" /* - * The set-digests here implement various "filters" that support - * "approximate member query". Conceptually these are like Bloom - * Filter and Quotient Filter, however, much smaller, faster, and - * designed to fit the requirements of our uses for glyph coverage - * queries. + * The set-digests implement "filters" that support "approximate + * member query". Conceptually these are like Bloom Filter and + * Quotient Filter, however, much smaller, faster, and designed + * to fit the requirements of our uses for glyph coverage queries. * * Our filters are highly accurate if the lookup covers fairly local * set of glyphs, but fully flooded and ineffective if coverage is diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-set.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-set.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-set.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-set.hh 2025-10-13 07:49:24.000000000 +0000 @@ -30,6 +30,7 @@ #include "hb.hh" #include "hb-bit-set-invertible.hh" +#include "hb-bit-vector.hh" // Just to include template diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-shape.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-shape.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-shape.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-shape.cc 2025-10-13 07:49:24.000000000 +0000 @@ -91,8 +91,10 @@ * * Retrieves the list of shapers supported by HarfBuzz. * - * Return value: (transfer none) (array zero-terminated=1): an array of - * constant strings + * Return value: (transfer none) (array zero-terminated=1): a + * `NULL`-terminated array of supported shapers constant string. + * The returned array is owned by HarfBuzz and should not be + * modified or freed. * * Since: 0.9.2 **/ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-static.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-static.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-static.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-static.cc 2025-10-13 07:49:24.000000000 +0000 @@ -41,6 +41,7 @@ #include "hb-ot-maxp-table.hh" #ifndef HB_NO_VISIBILITY + #include "hb-ot-name-language-static.hh" uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {}; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh 2025-10-13 07:49:24.000000000 +0000 @@ -570,7 +570,7 @@ parsed_cs_str_vec_t parsed_charstrings; parsed_cs_str_vec_t parsed_global_subrs; hb_vector_t parsed_local_subrs; - mutable hb_atomic_ptr_t glyph_to_sid_map; + mutable hb_atomic_t glyph_to_sid_map; private: hb_blob_t* original_blob; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc 2025-10-13 07:49:24.000000000 +0000 @@ -868,7 +868,7 @@ src = hb_utf8_t::next (src, src_end, &unicode, replacement); if (unicode >= 0x0080u) { - printf ("Non-ascii character detected, ignored...This API supports ascii characters only for mac platform\n"); + // Non-ascii character detected, ignored... return false; } } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc 2025-10-13 07:49:24.000000000 +0000 @@ -29,27 +29,21 @@ #include "hb-map.hh" #include "hb-multimap.hh" #include "hb-set.hh" +#include "hb-subset.h" +#include "hb-unicode.h" #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" #include "hb-ot-layout-base-table.hh" -#include "hb-ot-layout-gdef-table.hh" -#include "hb-ot-layout-gpos-table.hh" -#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-cff1-table.hh" #include "hb-ot-cff2-table.hh" #include "OT/Color/COLR/COLR.hh" #include "OT/Color/COLR/colrv1-closure.hh" #include "OT/Color/CPAL/CPAL.hh" #include "hb-ot-var-fvar-table.hh" -#include "hb-ot-var-avar-table.hh" #include "hb-ot-stat-table.hh" #include "hb-ot-math-table.hh" -using OT::Layout::GSUB; -using OT::Layout::GPOS; - - hb_subset_accelerator_t::~hb_subset_accelerator_t () { if (cmap_cache && destroy_cmap_cache) @@ -63,7 +57,6 @@ } -typedef hb_hashmap_t> script_langsys_map; #ifndef HB_NO_SUBSET_CFF static inline bool _add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff, @@ -98,414 +91,14 @@ } } -static void -_remap_indexes (const hb_set_t *indexes, - hb_map_t *mapping /* OUT */) +void +remap_indexes (const hb_set_t *indexes, + hb_map_t *mapping /* OUT */) { for (auto _ : + hb_enumerate (indexes->iter ())) mapping->set (_.second, _.first); - } -#ifndef HB_NO_SUBSET_LAYOUT - -/* - * Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates. - * Returns true if anything was removed (not including duplicates). - */ -static bool _filter_tag_list(hb_vector_t* tags, /* IN/OUT */ - const hb_set_t* filter) -{ - hb_vector_t out; - out.alloc (tags->get_size() + 1); // +1 is to allocate room for the null terminator. - - bool removed = false; - hb_set_t visited; - - for (hb_tag_t tag : *tags) - { - if (!tag) continue; - if (visited.has (tag)) continue; - - if (!filter->has (tag)) - { - removed = true; - continue; - } - - visited.add (tag); - out.push (tag); - } - - // The collect function needs a null element to signal end of the array. - out.push (HB_TAG_NONE); - - hb_swap (out, *tags); - return removed; -} - -template -static void _collect_layout_indices (hb_subset_plan_t *plan, - const T& table, - hb_set_t *lookup_indices, /* OUT */ - hb_set_t *feature_indices, /* OUT */ - hb_hashmap_t> *feature_record_cond_idx_map, /* OUT */ - hb_hashmap_t *feature_substitutes_map, /* OUT */ - hb_set_t& catch_all_record_feature_idxes, /* OUT */ - hb_hashmap_t>& catch_all_record_idx_feature_map /* OUT */) -{ - unsigned num_features = table.get_feature_count (); - hb_vector_t features; - if (!plan->check_success (features.resize (num_features))) return; - table.get_feature_tags (0, &num_features, features.arrayZ); - bool retain_all_features = !_filter_tag_list (&features, &plan->layout_features); - - unsigned num_scripts = table.get_script_count (); - hb_vector_t scripts; - if (!plan->check_success (scripts.resize (num_scripts))) return; - table.get_script_tags (0, &num_scripts, scripts.arrayZ); - bool retain_all_scripts = !_filter_tag_list (&scripts, &plan->layout_scripts); - - if (!plan->check_success (!features.in_error ()) || !features - || !plan->check_success (!scripts.in_error ()) || !scripts) - return; - - hb_ot_layout_collect_features (plan->source, - T::tableTag, - retain_all_scripts ? nullptr : scripts.arrayZ, - nullptr, - retain_all_features ? nullptr : features.arrayZ, - feature_indices); - -#ifndef HB_NO_VAR - // collect feature substitutes with variations - if (!plan->user_axes_location.is_empty ()) - { - hb_hashmap_t, unsigned> conditionset_map; - OT::hb_collect_feature_substitutes_with_var_context_t c = - { - &plan->axes_old_index_tag_map, - &plan->axes_location, - feature_record_cond_idx_map, - feature_substitutes_map, - catch_all_record_feature_idxes, - feature_indices, - false, - false, - false, - 0, - &conditionset_map - }; - table.collect_feature_substitutes_with_variations (&c); - } -#endif - - for (unsigned feature_index : *feature_indices) - { - const OT::Feature* f = &(table.get_feature (feature_index)); - const OT::Feature **p = nullptr; - if (feature_substitutes_map->has (feature_index, &p)) - f = *p; - - f->add_lookup_indexes_to (lookup_indices); - } - -#ifndef HB_NO_VAR - if (catch_all_record_feature_idxes) - { - for (unsigned feature_index : catch_all_record_feature_idxes) - { - const OT::Feature& f = table.get_feature (feature_index); - f.add_lookup_indexes_to (lookup_indices); - const void *tag = reinterpret_cast (&(table.get_feature_list ().get_tag (feature_index))); - catch_all_record_idx_feature_map.set (feature_index, hb_pair (&f, tag)); - } - } - - // If all axes are pinned then all feature variations will be dropped so there's no need - // to collect lookups from them. - if (!plan->all_axes_pinned) - table.feature_variation_collect_lookups (feature_indices, - plan->user_axes_location.is_empty () ? nullptr: feature_record_cond_idx_map, - lookup_indices); -#endif -} - - -static inline void -_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g, - const hb_map_t *lookup_indices, - const hb_set_t *feature_indices, - const hb_hashmap_t *feature_substitutes_map, - hb_map_t *duplicate_feature_map /* OUT */) -{ - if (feature_indices->is_empty ()) return; - hb_hashmap_t> unique_features; - //find out duplicate features after subset - for (unsigned i : feature_indices->iter ()) - { - hb_tag_t t = g.get_feature_tag (i); - if (t == HB_MAP_VALUE_INVALID) continue; - if (!unique_features.has (t)) - { - if (unlikely (!unique_features.set (t, hb::unique_ptr {hb_set_create ()}))) - return; - if (unique_features.has (t)) - unique_features.get (t)->add (i); - duplicate_feature_map->set (i, i); - continue; - } - - bool found = false; - - hb_set_t* same_tag_features = unique_features.get (t); - for (unsigned other_f_index : same_tag_features->iter ()) - { - const OT::Feature* f = &(g.get_feature (i)); - const OT::Feature **p = nullptr; - if (feature_substitutes_map->has (i, &p)) - f = *p; - - const OT::Feature* other_f = &(g.get_feature (other_f_index)); - if (feature_substitutes_map->has (other_f_index, &p)) - other_f = *p; - - auto f_iter = - + hb_iter (f->lookupIndex) - | hb_filter (lookup_indices) - ; - - auto other_f_iter = - + hb_iter (other_f->lookupIndex) - | hb_filter (lookup_indices) - ; - - bool is_equal = true; - for (; f_iter && other_f_iter; f_iter++, other_f_iter++) - { - unsigned a = *f_iter; - unsigned b = *other_f_iter; - if (a != b) { is_equal = false; break; } - } - - if (is_equal == false || f_iter || other_f_iter) continue; - - found = true; - duplicate_feature_map->set (i, other_f_index); - break; - } - - if (found == false) - { - same_tag_features->add (i); - duplicate_feature_map->set (i, i); - } - } -} - -template -static inline void -_closure_glyphs_lookups_features (hb_subset_plan_t *plan, - hb_set_t *gids_to_retain, - hb_map_t *lookups, - hb_map_t *features, - script_langsys_map *langsys_map, - hb_hashmap_t> *feature_record_cond_idx_map, - hb_hashmap_t *feature_substitutes_map, - hb_set_t &catch_all_record_feature_idxes, - hb_hashmap_t>& catch_all_record_idx_feature_map) -{ - hb_blob_ptr_t table = plan->source_table (); - hb_tag_t table_tag = table->tableTag; - hb_set_t lookup_indices, feature_indices; - _collect_layout_indices (plan, - *table, - &lookup_indices, - &feature_indices, - feature_record_cond_idx_map, - feature_substitutes_map, - catch_all_record_feature_idxes, - catch_all_record_idx_feature_map); - - if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE)) - hb_ot_layout_lookups_substitute_closure (plan->source, - &lookup_indices, - gids_to_retain); - table->closure_lookups (plan->source, - gids_to_retain, - &lookup_indices); - _remap_indexes (&lookup_indices, lookups); - - // prune features - table->prune_features (lookups, - plan->user_axes_location.is_empty () ? nullptr : feature_record_cond_idx_map, - feature_substitutes_map, - &feature_indices); - hb_map_t duplicate_feature_map; - _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map); - - feature_indices.clear (); - table->prune_langsys (&duplicate_feature_map, &plan->layout_scripts, langsys_map, &feature_indices); - _remap_indexes (&feature_indices, features); - - table.destroy (); -} - -#endif - -#ifndef HB_NO_VAR -static inline void -_generate_varstore_inner_maps (const hb_set_t& varidx_set, - unsigned subtable_count, - hb_vector_t &inner_maps /* OUT */) -{ - if (varidx_set.is_empty () || subtable_count == 0) return; - - if (unlikely (!inner_maps.resize (subtable_count))) return; - for (unsigned idx : varidx_set) - { - uint16_t major = idx >> 16; - uint16_t minor = idx & 0xFFFF; - - if (major >= subtable_count) - continue; - inner_maps[major].add (minor); - } -} - -static inline hb_font_t* -_get_hb_font_with_variations (const hb_subset_plan_t *plan) -{ - hb_font_t *font = hb_font_create (plan->source); - - hb_vector_t vars; - if (!vars.alloc (plan->user_axes_location.get_population ())) { - hb_font_destroy (font); - return nullptr; - } - - for (auto _ : plan->user_axes_location) - { - hb_variation_t var; - var.tag = _.first; - var.value = _.second.middle; - vars.push (var); - } - -#ifndef HB_NO_VAR - hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ()); -#endif - return font; -} - -static inline void -_remap_variation_indices (const OT::ItemVariationStore &var_store, - const hb_set_t &variation_indices, - const hb_vector_t& normalized_coords, - bool calculate_delta, /* not pinned at default */ - bool no_variations, /* all axes pinned */ - hb_hashmap_t> &variation_idx_delta_map /* OUT */) -{ - if (&var_store == &Null (OT::ItemVariationStore)) return; - unsigned subtable_count = var_store.get_sub_table_count (); - float *store_cache = var_store.create_cache (); - - unsigned new_major = 0, new_minor = 0; - unsigned last_major = (variation_indices.get_min ()) >> 16; - for (unsigned idx : variation_indices) - { - int delta = 0; - if (calculate_delta) - delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ, - normalized_coords.length, store_cache)); - - if (no_variations) - { - variation_idx_delta_map.set (idx, hb_pair_t (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta)); - continue; - } - - uint16_t major = idx >> 16; - if (major >= subtable_count) break; - if (major != last_major) - { - new_minor = 0; - ++new_major; - } - - unsigned new_idx = (new_major << 16) + new_minor; - variation_idx_delta_map.set (idx, hb_pair_t (new_idx, delta)); - ++new_minor; - last_major = major; - } - var_store.destroy_cache (store_cache); -} - -static inline void -_collect_layout_variation_indices (hb_subset_plan_t* plan) -{ - hb_blob_ptr_t gdef = plan->source_table (); - hb_blob_ptr_t gpos = plan->source_table (); - - if (!gdef->has_data () || !gdef->has_var_store ()) - { - gdef.destroy (); - gpos.destroy (); - return; - } - - hb_set_t varidx_set; - OT::hb_collect_variation_indices_context_t c (&varidx_set, - &plan->_glyphset_gsub, - &plan->gpos_lookups); - gdef->collect_variation_indices (&c); - - if (hb_ot_layout_has_positioning (plan->source)) - gpos->collect_variation_indices (&c); - - _remap_variation_indices (gdef->get_var_store (), - varidx_set, plan->normalized_coords, - !plan->pinned_at_default, - plan->all_axes_pinned, - plan->layout_variation_idx_delta_map); - - unsigned subtable_count = gdef->get_var_store ().get_sub_table_count (); - _generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps); - - gdef.destroy (); - gpos.destroy (); -} - -#ifndef HB_NO_BASE -static inline void -_collect_base_variation_indices (hb_subset_plan_t* plan) -{ - hb_blob_ptr_t base = plan->source_table (); - if (!base->has_var_store ()) - { - base.destroy (); - return; - } - - hb_set_t varidx_set; - base->collect_variation_indices (plan, varidx_set); - const OT::ItemVariationStore &var_store = base->get_var_store (); - unsigned subtable_count = var_store.get_sub_table_count (); - - - _remap_variation_indices (var_store, varidx_set, - plan->normalized_coords, - !plan->pinned_at_default, - plan->all_axes_pinned, - plan->base_variation_idx_map); - _generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps); - - base.destroy (); -} - -#endif -#endif - static inline void _cmap_closure (hb_face_t *face, const hb_set_t *unicodes, @@ -515,41 +108,6 @@ cmap.table->closure_glyphs (unicodes, glyphset); } -#ifndef HB_NO_VAR -static void -_remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map, - const hb_set_t &delta_set_idxes, - hb_hashmap_t> &variation_idx_delta_map, /* IN/OUT */ - hb_map_t &new_deltaset_idx_varidx_map /* OUT */) -{ - if (!index_map.get_map_count ()) - return; - - hb_hashmap_t> delta_set_idx_delta_map; - unsigned new_delta_set_idx = 0; - for (unsigned delta_set_idx : delta_set_idxes) - { - unsigned var_idx = index_map.map (delta_set_idx); - unsigned new_varidx = HB_OT_LAYOUT_NO_VARIATIONS_INDEX; - int delta = 0; - - if (var_idx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) - { - hb_pair_t *new_varidx_delta; - if (!variation_idx_delta_map.has (var_idx, &new_varidx_delta)) continue; - - new_varidx = hb_first (*new_varidx_delta); - delta = hb_second (*new_varidx_delta); - } - - new_deltaset_idx_varidx_map.set (new_delta_set_idx, new_varidx); - delta_set_idx_delta_map.set (delta_set_idx, hb_pair_t (new_delta_set_idx, delta)); - new_delta_set_idx++; - } - variation_idx_delta_map = std::move (delta_set_idx_delta_map); -} -#endif - static void _colr_closure (hb_subset_plan_t* plan, hb_set_t *glyphs_colred) { @@ -569,7 +127,7 @@ colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices, &variation_indices, &delta_set_indices); colr.closure_V0palette_indices (glyphs_colred, &palette_indices); - _remap_indexes (&layer_indices, &plan->colrv1_layers); + remap_indexes (&layer_indices, &plan->colrv1_layers); _remap_palette_indexes (&palette_indices, &plan->colr_palettes); #ifndef HB_NO_VAR @@ -578,7 +136,7 @@ const OT::ItemVariationStore &var_store = colr.get_var_store (); // generated inner_maps is used by ItemVariationStore serialize(), which is subset only unsigned subtable_count = var_store.get_sub_table_count (); - _generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps); + generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps); /* colr variation indices mapping during planning phase: * generate colrv1_variation_idx_delta_map. When delta set index map is not @@ -590,7 +148,7 @@ * instancing. */ if (!plan->all_axes_pinned) { - _remap_variation_indices (var_store, + remap_variation_indices (var_store, variation_indices, plan->normalized_coords, false, /* no need to calculate delta for COLR during planning */ @@ -598,7 +156,7 @@ plan->colrv1_variation_idx_delta_map); if (colr.has_delta_set_index_map ()) - _remap_colrv1_delta_set_index_indices (colr.get_delta_set_index_map (), + remap_colrv1_delta_set_index_indices (colr.get_delta_set_index_map (), delta_set_indices, plan->colrv1_variation_idx_delta_map, plan->colrv1_new_deltaset_idx_varidx_map); @@ -617,25 +175,6 @@ } static inline void -_remap_used_mark_sets (hb_subset_plan_t *plan, - hb_map_t& used_mark_sets_map) -{ - hb_blob_ptr_t gdef = plan->source_table (); - - if (!gdef->has_data () || !gdef->has_mark_glyph_sets ()) - { - gdef.destroy (); - return; - } - - hb_set_t used_mark_sets; - gdef->get_mark_glyph_sets ().collect_used_mark_sets (plan->_glyphset_gsub, used_mark_sets); - gdef.destroy (); - - _remap_indexes (&used_mark_sets, &used_mark_sets_map); -} - -static inline void _remove_invalid_gids (hb_set_t *glyphs, unsigned int num_glyphs) { @@ -672,15 +211,46 @@ _fill_unicode_and_glyph_map(plan, unicode_iterator, unicode_to_gid_for_iterator, unicode_to_gid_for_iterator); } +/* + * Finds additional unicode codepoints which are reachable from the input unicode set. + * Currently this adds in mirrored variants (needed for bidi) of any input unicodes. + */ +static hb_set_t +_unicode_closure (const hb_set_t* unicodes, bool bidi_closure) { + // TODO: we may want to also consider pulling in reachable unicode composition and decompositions. + // see: https://github.com/harfbuzz/harfbuzz/issues/2283 + hb_set_t out = *unicodes; + if (!bidi_closure) return out; + + if (out.is_inverted()) { + // don't closure inverted sets, they are asking to specifically exclude certain codepoints. + // otherwise everything is already included. + return out; + } + + auto unicode_funcs = hb_unicode_funcs_get_default (); + for (hb_codepoint_t cp : *unicodes) { + hb_codepoint_t mirror = hb_unicode_mirroring(unicode_funcs, cp); + if (unlikely (mirror != cp)) { + out.add(mirror); + } + } + + return out; +} + static void -_populate_unicodes_to_retain (const hb_set_t *unicodes, +_populate_unicodes_to_retain (const hb_set_t *unicodes_in, const hb_set_t *glyphs, hb_subset_plan_t *plan) { + hb_set_t unicodes = _unicode_closure(unicodes_in, + !(plan->flags & HB_SUBSET_FLAGS_NO_BIDI_CLOSURE)); + OT::cmap::accelerator_t cmap (plan->source); unsigned size_threshold = plan->source->get_num_glyphs (); - if (glyphs->is_empty () && unicodes->get_population () < size_threshold) + if (glyphs->is_empty () && unicodes.get_population () < size_threshold) { const hb_map_t* unicode_to_gid = nullptr; @@ -690,9 +260,9 @@ // This is approach to collection is faster, but can only be used if glyphs // are not being explicitly added to the subset and the input unicodes set is // not excessively large (eg. an inverted set). - plan->unicode_to_new_gid_list.alloc (unicodes->get_population ()); + plan->unicode_to_new_gid_list.alloc (unicodes.get_population ()); if (!unicode_to_gid) { - _fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) { + _fill_unicode_and_glyph_map(plan, unicodes.iter(), [&] (hb_codepoint_t cp) { hb_codepoint_t gid; if (!cmap.get_nominal_glyph (cp, &gid)) { return HB_MAP_VALUE_INVALID; @@ -704,7 +274,7 @@ // the map. This code is mostly duplicated from above to avoid doing // conditionals on the presence of the unicode_to_gid map each // iteration. - _fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) { + _fill_unicode_and_glyph_map(plan, unicodes.iter(), [&] (hb_codepoint_t cp) { return unicode_to_gid->get (cp); }); } @@ -721,7 +291,7 @@ if (!plan->accelerator) { cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage); - plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population () + plan->unicode_to_new_gid_list.alloc (hb_min(unicodes.get_population () + glyphs->get_population (), cmap_unicodes->get_population ())); } else { @@ -730,10 +300,10 @@ } if (plan->accelerator && - unicodes->get_population () < cmap_unicodes->get_population () && + unicodes.get_population () < cmap_unicodes->get_population () && glyphs->get_population () < cmap_unicodes->get_population ()) { - plan->codepoint_to_glyph->alloc (unicodes->get_population () + glyphs->get_population ()); + plan->codepoint_to_glyph->alloc (unicodes.get_population () + glyphs->get_population ()); auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes; @@ -748,7 +318,7 @@ }); } - _fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) { + _fill_unicode_and_glyph_map(plan, unicodes.iter(), [&] (hb_codepoint_t cp) { /* Don't double-add entry. */ if (plan->codepoint_to_glyph->has (cp)) return HB_MAP_VALUE_INVALID; @@ -769,7 +339,7 @@ { _fill_unicode_and_glyph_map(plan, hb_range(first, last + 1), [&] (hb_codepoint_t cp) { hb_codepoint_t gid = (*unicode_glyphid_map)[cp]; - if (!unicodes->has (cp) && !glyphs->has (gid)) + if (!unicodes.has (cp) && !glyphs->has (gid)) return HB_MAP_VALUE_INVALID; return gid; }, @@ -860,18 +430,7 @@ #endif #ifndef HB_NO_SUBSET_LAYOUT - if (!drop_tables->has (HB_OT_TAG_GPOS)) - { - hb_blob_ptr_t gpos = plan->source_table (); - gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids); - gpos.destroy (); - } - if (!drop_tables->has (HB_OT_TAG_GSUB)) - { - hb_blob_ptr_t gsub = plan->source_table (); - gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids); - gsub.destroy (); - } + layout_nameid_closure(plan, drop_tables); #endif } @@ -893,31 +452,9 @@ _cmap_closure (plan->source, &plan->unicodes, &plan->_glyphset_gsub); #ifndef HB_NO_SUBSET_LAYOUT - if (!drop_tables->has (HB_OT_TAG_GSUB)) - // closure all glyphs/lookups/features needed for GSUB substitutions. - _closure_glyphs_lookups_features ( - plan, - &plan->_glyphset_gsub, - &plan->gsub_lookups, - &plan->gsub_features, - &plan->gsub_langsys, - &plan->gsub_feature_record_cond_idx_map, - &plan->gsub_feature_substitutes_map, - plan->gsub_old_features, - plan->gsub_old_feature_idx_tag_map); - - if (!drop_tables->has (HB_OT_TAG_GPOS)) - _closure_glyphs_lookups_features ( - plan, - &plan->_glyphset_gsub, - &plan->gpos_lookups, - &plan->gpos_features, - &plan->gpos_langsys, - &plan->gpos_feature_record_cond_idx_map, - &plan->gpos_feature_substitutes_map, - plan->gpos_old_features, - plan->gpos_old_feature_idx_tag_map); + layout_populate_gids_to_retain(plan, drop_tables); #endif + _remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ()); plan->_glyphset_mathed = plan->_glyphset_gsub; @@ -962,8 +499,10 @@ _remove_invalid_gids (&plan->_glyphset, plan->source->get_num_glyphs ()); #ifndef HB_NO_VAR +#ifndef HB_NO_SUBSET_LAYOUT if (!drop_tables->has (HB_OT_TAG_GDEF)) - _collect_layout_variation_indices (plan); + collect_layout_variation_indices (plan); +#endif #endif } @@ -1077,193 +616,6 @@ return true; } -#ifndef HB_NO_VAR -static void -_normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) -{ - if (plan->user_axes_location.is_empty ()) - return; - - hb_array_t axes = face->table.fvar->get_axes (); - plan->normalized_coords.resize (axes.length); - - bool has_avar = face->table.avar->has_data (); - const OT::SegmentMaps *seg_maps = nullptr; - unsigned avar_axis_count = 0; - if (has_avar) - { - seg_maps = face->table.avar->get_segment_maps (); - avar_axis_count = face->table.avar->get_axis_count(); - } - - bool axis_not_pinned = false; - unsigned old_axis_idx = 0, new_axis_idx = 0; - for (const auto& axis : axes) - { - hb_tag_t axis_tag = axis.get_axis_tag (); - plan->axes_old_index_tag_map.set (old_axis_idx, axis_tag); - - if (!plan->user_axes_location.has (axis_tag) || - !plan->user_axes_location.get (axis_tag).is_point ()) - { - axis_not_pinned = true; - plan->axes_index_map.set (old_axis_idx, new_axis_idx); - plan->axis_tags.push (axis_tag); - new_axis_idx++; - } - - Triple *axis_range; - if (plan->user_axes_location.has (axis_tag, &axis_range)) - { - plan->axes_triple_distances.set (axis_tag, axis.get_triple_distances ()); - - int normalized_min = axis.normalize_axis_value (axis_range->minimum); - int normalized_default = axis.normalize_axis_value (axis_range->middle); - int normalized_max = axis.normalize_axis_value (axis_range->maximum); - - if (has_avar && old_axis_idx < avar_axis_count) - { - normalized_min = seg_maps->map (normalized_min); - normalized_default = seg_maps->map (normalized_default); - normalized_max = seg_maps->map (normalized_max); - } - plan->axes_location.set (axis_tag, Triple (static_cast (normalized_min / 16384.0), - static_cast (normalized_default / 16384.0), - static_cast (normalized_max / 16384.0))); - - if (normalized_default != 0) - plan->pinned_at_default = false; - - plan->normalized_coords[old_axis_idx] = normalized_default; - } - - old_axis_idx++; - - if (has_avar && old_axis_idx < avar_axis_count) - seg_maps = &StructAfter (*seg_maps); - } - plan->all_axes_pinned = !axis_not_pinned; -} - -static void -_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan) -{ - if (!plan->normalized_coords) return; - OT::cff2::accelerator_t cff2 (plan->source); - if (!cff2.is_valid ()) return; - - hb_font_t *font = _get_hb_font_with_variations (plan); - if (unlikely (!plan->check_success (font != nullptr))) - { - hb_font_destroy (font); - return; - } - - hb_glyph_extents_t extents = {0x7FFF, -0x7FFF}; - OT::hmtx_accelerator_t _hmtx (plan->source); - float *hvar_store_cache = nullptr; - if (_hmtx.has_data () && _hmtx.var_table.get_length ()) - hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache (); - - OT::vmtx_accelerator_t _vmtx (plan->source); - float *vvar_store_cache = nullptr; - if (_vmtx.has_data () && _vmtx.var_table.get_length ()) - vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache (); - - for (auto p : *plan->glyph_map) - { - hb_codepoint_t old_gid = p.first; - hb_codepoint_t new_gid = p.second; - if (!cff2.get_extents (font, old_gid, &extents)) continue; - bool has_bounds_info = true; - if (extents.x_bearing == 0 && extents.width == 0 && - extents.height == 0 && extents.y_bearing == 0) - has_bounds_info = false; - - if (has_bounds_info) - { - plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing); - plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width); - plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing); - plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height); - } - - if (_hmtx.has_data ()) - { - int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid); - if (_hmtx.var_table.get_length ()) - hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords, - hvar_store_cache)); - int lsb = extents.x_bearing; - if (!has_bounds_info) - { - if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) - continue; - } - plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb)); - plan->bounds_width_vec[new_gid] = extents.width; - } - - if (_vmtx.has_data ()) - { - int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid); - if (_vmtx.var_table.get_length ()) - vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords, - vvar_store_cache)); - - int tsb = extents.y_bearing; - if (!has_bounds_info) - { - if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb)) - continue; - } - plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb)); - plan->bounds_height_vec[new_gid] = extents.height; - } - } - hb_font_destroy (font); - if (hvar_store_cache) - _hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache); - if (vvar_store_cache) - _vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache); -} - -static bool -_get_instance_glyphs_contour_points (hb_subset_plan_t *plan) -{ - /* contour_points vector only needed for updating gvar table (infer delta and - * iup delta optimization) during partial instancing */ - if (plan->user_axes_location.is_empty () || plan->all_axes_pinned) - return true; - - OT::glyf_accelerator_t glyf (plan->source); - - for (auto &_ : plan->new_to_old_gid_list) - { - hb_codepoint_t new_gid = _.first; - contour_point_vector_t all_points; - if (new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) - { - if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points))) - return false; - continue; - } - - hb_codepoint_t old_gid = _.second; - auto glyph = glyf.glyph_for_gid (old_gid); - if (unlikely (!glyph.get_all_points_without_var (plan->source, all_points))) - return false; - if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points))) - return false; - - /* composite new gids are only needed by iup delta optimization */ - if ((plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS) && glyph.is_composite ()) - plan->composite_new_gids.add (new_gid); - } - return true; -} -#endif - hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, const hb_subset_input_t *input) { @@ -1324,7 +676,7 @@ return; #ifndef HB_NO_VAR - _normalize_axes_location (face, this); + normalize_axes_location (face, this); #endif _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this); @@ -1365,13 +717,15 @@ for (auto &v : bounds_height_vec) v = 0xFFFFFFFF; +#ifndef HB_NO_SUBSET_LAYOUT if (!drop_tables.has (HB_OT_TAG_GDEF)) - _remap_used_mark_sets (this, used_mark_sets_map); + remap_used_mark_sets (this, used_mark_sets_map); +#endif #ifndef HB_NO_VAR #ifndef HB_NO_BASE if (!drop_tables.has (HB_OT_TAG_BASE)) - _collect_base_variation_indices (this); + collect_base_variation_indices (this); #endif #endif @@ -1379,8 +733,8 @@ return; #ifndef HB_NO_VAR - _update_instance_metrics_map_from_cff2 (this); - if (!check_success (_get_instance_glyphs_contour_points (this))) + update_instance_metrics_map_from_cff2 (this); + if (!check_success (get_instance_glyphs_contour_points (this))) return; #endif diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh 2025-10-13 07:49:24.000000000 +0000 @@ -296,5 +296,75 @@ } }; +// hb-subset-plan implementation is split into multiple files to keep +// compile times more reasonable: +// - hb-subset-plan.cc +// - hb-subset-plan-layout.cc +// +// The functions below are those needed to connect the split files +// above together. +HB_INTERNAL void +remap_indexes (const hb_set_t *indexes, + hb_map_t *mapping /* OUT */); + + +#ifndef HB_NO_VAR +template +HB_INTERNAL void +remap_variation_indices (const ItemVarStore &var_store, + const hb_set_t &variation_indices, + const hb_vector_t& normalized_coords, + bool calculate_delta, /* not pinned at default */ + bool no_variations, /* all axes pinned */ + hb_hashmap_t> &variation_idx_delta_map /* OUT */); + + +template +HB_INTERNAL void +remap_colrv1_delta_set_index_indices (const DeltaSetIndexMap &index_map, + const hb_set_t &delta_set_idxes, + hb_hashmap_t> &variation_idx_delta_map, /* IN/OUT */ + hb_map_t &new_deltaset_idx_varidx_map /* OUT */); + + +HB_INTERNAL void +generate_varstore_inner_maps (const hb_set_t& varidx_set, + unsigned subtable_count, + hb_vector_t &inner_maps /* OUT */); + +HB_INTERNAL void +normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan); + +HB_INTERNAL void +update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan); + +HB_INTERNAL bool +get_instance_glyphs_contour_points (hb_subset_plan_t *plan); + +#ifndef HB_NO_BASE +HB_INTERNAL void +collect_base_variation_indices (hb_subset_plan_t* plan); +#endif +#endif + +#ifndef HB_NO_SUBSET_LAYOUT +typedef hb_hashmap_t> script_langsys_map; + +HB_INTERNAL void +remap_used_mark_sets (hb_subset_plan_t *plan, + hb_map_t& used_mark_sets_map); + +HB_INTERNAL void +layout_nameid_closure (hb_subset_plan_t* plan, + hb_set_t* drop_tables); + +HB_INTERNAL void +layout_populate_gids_to_retain (hb_subset_plan_t* plan, + hb_set_t* drop_tables); + +HB_INTERNAL void +collect_layout_variation_indices (hb_subset_plan_t* plan); +#endif + #endif /* HB_SUBSET_PLAN_HH */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset.cc openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset.cc --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset.cc 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset.cc 2025-10-13 07:49:24.000000000 +0000 @@ -708,3 +708,107 @@ end: return success ? hb_face_reference (plan->dest) : nullptr; } + + +#ifdef HB_EXPERIMENTAL_API + +#include "hb-ot-cff1-table.hh" + +template +static hb_blob_t* get_charstrings_data(accel_t& accel, hb_codepoint_t glyph_index) { + if (!accel.is_valid()) { + return hb_blob_get_empty (); + } + + hb_ubytes_t bytes = (*accel.charStrings)[glyph_index]; + if (!bytes) { + return hb_blob_get_empty (); + } + + hb_blob_t* cff_blob = accel.get_blob(); + uint32_t length; + const char* cff_data = hb_blob_get_data(cff_blob, &length) ; + + long int offset = (const char*) bytes.arrayZ - cff_data; + if (offset < 0 || offset > INT32_MAX) { + return hb_blob_get_empty (); + } + + return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, bytes.length); +} + +template +static hb_blob_t* get_charstrings_index(accel_t& accel) { + if (!accel.is_valid()) { + return hb_blob_get_empty (); + } + + const char* charstrings_start = (const char*) accel.charStrings; + unsigned charstrings_length = accel.charStrings->get_size(); + + hb_blob_t* cff_blob = accel.get_blob(); + uint32_t length; + const char* cff_data = hb_blob_get_data(cff_blob, &length) ; + + long int offset = charstrings_start - cff_data; + if (offset < 0 || offset > INT32_MAX) { + return hb_blob_get_empty (); + } + + return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, charstrings_length); +} + +/** + * hb_subset_cff_get_charstring_data: + * @face: A face object + * @glyph_index: Glyph index to get data for. + * + * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { + return get_charstrings_data(*face->table.cff1, glyph_index); +} + +/** + * hb_subset_cff_get_charstrings_index: + * @face: A face object + * + * Returns the raw CFF CharStrings INDEX from the CFF table. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff_get_charstrings_index (hb_face_t* face) { + return get_charstrings_index (*face->table.cff1); +} + +/** + * hb_subset_cff2_get_charstring_data: + * @face: A face object + * @glyph_index: Glyph index to get data for. + * + * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { + return get_charstrings_data(*face->table.cff2, glyph_index); +} + +/** + * hb_subset_cff2_get_charstrings_index: + * @face: A face object + * + * Returns the raw CFF2 CharStrings INDEX from the CFF2 table. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff2_get_charstrings_index (hb_face_t* face) { + return get_charstrings_index (*face->table.cff2); +} +#endif \ No newline at end of file diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-subset.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-subset.h 2025-10-13 07:49:24.000000000 +0000 @@ -71,10 +71,12 @@ * in the final subset. * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in * OS/2 will not be recalculated. - * @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout + * @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set do not perform glyph closure on layout * substitution rules (GSUB). Since: 7.2.0. * @HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS: If set perform IUP delta optimization on the * remaining gvar table's deltas. Since: 8.5.0 + * @HB_SUBSET_FLAGS_NO_BIDI_CLOSURE: If set do not pull mirrored versions of input + * codepoints into the subset. Since: 11.1.0 * @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset * to allow it to be used with incremental font transfer IFTB patches. Primarily, * this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL @@ -96,8 +98,9 @@ HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u, HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u, HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS = 0x00000400u, + HB_SUBSET_FLAGS_NO_BIDI_CLOSURE = 0x00000800u, #ifdef HB_EXPERIMENTAL_API - HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00000800u, + HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00001000u, #endif } hb_subset_flags_t; @@ -224,6 +227,23 @@ unsigned language_id, const char *name_str, int str_len); + + +/* +* Raw outline data access +*/ + +HB_EXTERN hb_blob_t* +hb_subset_cff_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph_index); + +HB_EXTERN hb_blob_t* +hb_subset_cff_get_charstrings_index (hb_face_t* face); + +HB_EXTERN hb_blob_t* +hb_subset_cff2_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph_index); + +HB_EXTERN hb_blob_t* +hb_subset_cff2_get_charstrings_index (hb_face_t* face); #endif HB_EXTERN hb_face_t * diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-vector.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-vector.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-vector.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-vector.hh 2025-10-13 07:49:24.000000000 +0000 @@ -90,7 +90,13 @@ { auto iter = hb_iter (o); if (iter.is_random_access_iterator || iter.has_fast_len) - alloc (hb_len (iter), true); + { + if (unlikely (!alloc (hb_len (iter), true))) + return; + unsigned count = hb_len (iter); + for (unsigned i = 0; i < count; i++) + push_has_room (*iter++); + } while (iter) { if (unlikely (!alloc (length + 1))) @@ -436,7 +442,6 @@ new_allocated += (new_allocated >> 1) + 8; } - /* Reallocate */ bool overflows = diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-version.h openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-version.h --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb-version.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb-version.h 2025-10-13 07:49:24.000000000 +0000 @@ -41,13 +41,13 @@ * * The major component of the library version available at compile-time. */ -#define HB_VERSION_MAJOR 10 +#define HB_VERSION_MAJOR 11 /** * HB_VERSION_MINOR: * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 4 +#define HB_VERSION_MINOR 2 /** * HB_VERSION_MICRO: * @@ -60,7 +60,7 @@ * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "10.4.0" +#define HB_VERSION_STRING "11.2.0" /** * HB_VERSION_ATLEAST: diff -Nru openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb.hh openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb.hh --- openjdk-21-21.0.8+9/src/java.desktop/share/native/libharfbuzz/hb.hh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/share/native/libharfbuzz/hb.hh 2025-10-13 07:49:24.000000000 +0000 @@ -89,6 +89,7 @@ #pragma GCC diagnostic error "-Wstring-conversion" #pragma GCC diagnostic error "-Wswitch-enum" #pragma GCC diagnostic error "-Wtautological-overlap-compare" +#pragma GCC diagnostic error "-Wuninitialized" #pragma GCC diagnostic error "-Wunneeded-internal-declaration" #pragma GCC diagnostic error "-Wunused" #pragma GCC diagnostic error "-Wunused-local-typedefs" @@ -230,33 +231,6 @@ #define HB_PASTE(a,b) HB_PASTE1(a,b) -/* Compile-time custom allocator support. */ - -#if !defined(HB_CUSTOM_MALLOC) \ - && defined(hb_malloc_impl) \ - && defined(hb_calloc_impl) \ - && defined(hb_realloc_impl) \ - && defined(hb_free_impl) -#define HB_CUSTOM_MALLOC -#endif - -#ifdef HB_CUSTOM_MALLOC -extern "C" void* hb_malloc_impl(size_t size); -extern "C" void* hb_calloc_impl(size_t nmemb, size_t size); -extern "C" void* hb_realloc_impl(void *ptr, size_t size); -extern "C" void hb_free_impl(void *ptr); -#define hb_malloc hb_malloc_impl -#define hb_calloc hb_calloc_impl -#define hb_realloc hb_realloc_impl -#define hb_free hb_free_impl -#else -#define hb_malloc malloc -#define hb_calloc calloc -#define hb_realloc realloc -#define hb_free free -#endif - - /* * Compiler attributes */ @@ -282,7 +256,7 @@ #define __attribute__(x) #endif -#if defined(__MINGW32__) && (__GNUC__ >= 3) +#if defined(__MINGW32__) && (__GNUC__ >= 3) && !defined(__clang__) #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (gnu_printf, format_idx, arg_idx))) #elif defined(__GNUC__) && (__GNUC__ >= 3) #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx))) @@ -491,7 +465,7 @@ # define hb_atexit atexit # else template struct hb_atexit_t { ~hb_atexit_t () { function (); } }; -# define hb_atexit(f) static hb_atexit_t _hb_atexit_##__LINE__; +# define hb_atexit(f) static hb_atexit_t _hb_atexit_##__LINE__ # endif #endif #endif @@ -539,6 +513,29 @@ #define HB_PI 3.14159265358979f #define HB_2_PI (2.f * HB_PI) +/* Compile-time custom allocator support. */ + +#if !defined(HB_CUSTOM_MALLOC) \ + && defined(hb_malloc_impl) \ + && defined(hb_calloc_impl) \ + && defined(hb_realloc_impl) \ + && defined(hb_free_impl) +#define HB_CUSTOM_MALLOC +#endif + +#ifdef HB_CUSTOM_MALLOC +extern "C" void* hb_malloc_impl(size_t size); +extern "C" void* hb_calloc_impl(size_t nmemb, size_t size); +extern "C" void* hb_realloc_impl(void *ptr, size_t size); +extern "C" void hb_free_impl(void *ptr); +#else +#define hb_malloc_impl malloc +#define hb_calloc_impl calloc +#define hb_realloc_impl realloc +#define hb_free_impl free +#endif + + /* Headers we include for everyone. Keep topologically sorted by dependency. * They express dependency amongst themselves, but no other file should include diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/PlatformGraphicsInfo.java openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/PlatformGraphicsInfo.java --- openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/PlatformGraphicsInfo.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/PlatformGraphicsInfo.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -93,7 +93,6 @@ No X11 DISPLAY variable was set, or no headful library support was found, - but this program performed an operation which requires it, - """; + but this program performed an operation which requires it."""; } } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java --- openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java 2025-10-13 07:49:24.000000000 +0000 @@ -50,7 +50,6 @@ import java.awt.image.WritableRaster; import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; @@ -280,14 +279,12 @@ return result; } - private Integer getGnomeShellMajorVersion() { + public Integer getGnomeShellMajorVersion() { try { Process process = new ProcessBuilder("/usr/bin/gnome-shell", "--version") .start(); - try (InputStreamReader isr = new InputStreamReader(process.getInputStream()); - BufferedReader reader = new BufferedReader(isr)) { - + try (BufferedReader reader = process.inputReader()) { if (process.waitFor(2, SECONDS) && process.exitValue() == 0) { String line = reader.readLine(); if (line != null) { diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java --- openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -36,15 +36,13 @@ import sun.awt.X11GraphicsConfig; import sun.awt.X11GraphicsDevice; import sun.awt.screencast.ScreencastHelper; +import sun.awt.screencast.XdgDesktopPortal; import sun.security.action.GetPropertyAction; @SuppressWarnings("removal") final class XRobotPeer implements RobotPeer { private static final boolean tryGtk; - private static final String screenshotMethod; - private static final String METHOD_X11 = "x11"; - private static final String METHOD_SCREENCAST = "dbusScreencast"; static { loadNativeLibraries(); @@ -54,20 +52,6 @@ new GetPropertyAction("awt.robot.gtk", "true") )); - - boolean isOnWayland = false; - - if (Toolkit.getDefaultToolkit() instanceof SunToolkit sunToolkit) { - isOnWayland = sunToolkit.isRunningOnWayland(); - } - - screenshotMethod = AccessController.doPrivileged( - new GetPropertyAction( - "awt.robot.screenshotMethod", - isOnWayland - ? METHOD_SCREENCAST - : METHOD_X11 - )); } private static volatile boolean useGtk; @@ -92,39 +76,63 @@ @Override public void mouseMove(int x, int y) { mouseMoveImpl(xgc, xgc.scaleUp(x), xgc.scaleUp(y)); + if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) { + // We still call mouseMoveImpl on purpose to change the mouse position + // within the XWayland server so that we can retrieve it later. + ScreencastHelper.remoteDesktopMouseMove(xgc.scaleUp(x), xgc.scaleUp(y)); + } } @Override public void mousePress(int buttons) { - mousePressImpl(buttons); + if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) { + ScreencastHelper.remoteDesktopMouseButton(true, buttons); + } else { + mousePressImpl(buttons); + } } @Override public void mouseRelease(int buttons) { - mouseReleaseImpl(buttons); + if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) { + ScreencastHelper.remoteDesktopMouseButton(false, buttons); + } else { + mouseReleaseImpl(buttons); + } } @Override public void mouseWheel(int wheelAmt) { - mouseWheelImpl(wheelAmt); + if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) { + ScreencastHelper.remoteDesktopMouseWheel(wheelAmt); + } else { + mouseWheelImpl(wheelAmt); + } } @Override public void keyPress(int keycode) { - keyPressImpl(keycode); + if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) { + ScreencastHelper.remoteDesktopKey(true, keycode); + } else { + keyPressImpl(keycode); + } } @Override public void keyRelease(int keycode) { - keyReleaseImpl(keycode); + if (XdgDesktopPortal.isRemoteDesktop() && ScreencastHelper.isAvailable()) { + ScreencastHelper.remoteDesktopKey(false, keycode); + } else { + keyReleaseImpl(keycode); + } } @Override public int getRGBPixel(int x, int y) { int[] pixelArray = new int[1]; - if (screenshotMethod.equals(METHOD_SCREENCAST) - && ScreencastHelper.isAvailable()) { - + if ((XdgDesktopPortal.isScreencast() + || XdgDesktopPortal.isRemoteDesktop()) && ScreencastHelper.isAvailable()) { ScreencastHelper.getRGBPixels(x, y, 1, 1, pixelArray); } else { getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray, useGtk); @@ -135,8 +143,8 @@ @Override public int[] getRGBPixels(Rectangle bounds) { int[] pixelArray = new int[bounds.width * bounds.height]; - if (screenshotMethod.equals(METHOD_SCREENCAST) - && ScreencastHelper.isAvailable()) { + if ((XdgDesktopPortal.isScreencast() + || XdgDesktopPortal.isRemoteDesktop()) && ScreencastHelper.isAvailable()) { ScreencastHelper.getRGBPixels(bounds.x, bounds.y, bounds.width, bounds.height, diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java --- openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -142,6 +142,8 @@ import sun.awt.X11GraphicsEnvironment; import sun.awt.XSettings; import sun.awt.datatransfer.DataTransferer; +import sun.awt.screencast.ScreencastHelper; +import sun.awt.screencast.XdgDesktopPortal; import sun.awt.util.PerformanceLogger; import sun.awt.util.ThreadGroupUtils; import sun.font.FontConfigManager; @@ -1565,16 +1567,21 @@ awtLock(); try { if (numberOfButtons == 0) { - numberOfButtons = getNumberOfButtonsImpl(); - numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons; - //4th and 5th buttons are for wheel and shouldn't be reported as buttons. - //If we have more than 3 physical buttons and a wheel, we report N-2 buttons. - //If we have 3 physical buttons and a wheel, we report 3 buttons. - //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively. - if (numberOfButtons >=5) { - numberOfButtons -= 2; - } else if (numberOfButtons == 4 || numberOfButtons ==5){ + if (XdgDesktopPortal.isRemoteDesktop() + && ScreencastHelper.isAvailable()) { numberOfButtons = 3; + } else { + numberOfButtons = getNumberOfButtonsImpl(); + numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons; + //4th and 5th buttons are for wheel and shouldn't be reported as buttons. + //If we have more than 3 physical buttons and a wheel, we report N-2 buttons. + //If we have 3 physical buttons and a wheel, we report 3 buttons. + //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively. + if (numberOfButtons >= 5) { + numberOfButtons -= 2; + } else if (numberOfButtons == 4 || numberOfButtons == 5) { + numberOfButtons = 3; + } } } //Assume don't have to re-query the number again and again. diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java --- openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java 2025-10-13 07:49:24.000000000 +0000 @@ -339,7 +339,7 @@ private static native void enterFullScreenExclusive(long window); private static native void exitFullScreenExclusive(long window); - private static native boolean initXrandrExtension(); + private static native boolean initXrandrExtension(boolean useOldConfigDisplayMode); private static native DisplayMode getCurrentDisplayMode(int screen); private static native void enumDisplayModes(int screen, ArrayList modes); @@ -356,10 +356,11 @@ */ private static synchronized boolean isXrandrExtensionSupported() { if (xrandrExtSupported == null) { - xrandrExtSupported = - Boolean.valueOf(initXrandrExtension()); + boolean useOldConfigDisplayMode = + Boolean.getBoolean("awt.x11useOldConfigDisplayMode"); + xrandrExtSupported = initXrandrExtension(useOldConfigDisplayMode); } - return xrandrExtSupported.booleanValue(); + return xrandrExtSupported; } @Override diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java --- openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 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 @@ -40,6 +40,7 @@ import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import java.util.function.Function; import java.util.stream.IntStream; /** @@ -54,10 +55,13 @@ static final boolean SCREENCAST_DEBUG; private static final boolean IS_NATIVE_LOADED; - private static final int ERROR = -1; private static final int DENIED = -11; private static final int OUT_OF_BOUNDS = -12; + private static final int NO_STREAMS = -13; + + private static final int XDG_METHOD_SCREENCAST = 0; + private static final int XDG_METHOD_REMOTE_DESKTOP = 1; private static final int DELAY_BEFORE_SESSION_CLOSE = 2000; @@ -66,8 +70,7 @@ = new Timer("auto-close screencast session", true); - private ScreencastHelper() { - } + private ScreencastHelper() {} static { SCREENCAST_DEBUG = Boolean.parseBoolean( @@ -80,9 +83,16 @@ boolean loadFailed = false; + boolean shouldLoadNative = XdgDesktopPortal.isRemoteDesktop() + || XdgDesktopPortal.isScreencast(); + + int methodId = XdgDesktopPortal.isScreencast() + ? XDG_METHOD_SCREENCAST + : XDG_METHOD_REMOTE_DESKTOP; + if (!(Toolkit.getDefaultToolkit() instanceof UNIXToolkit tk && tk.loadGTK()) - || !loadPipewire(SCREENCAST_DEBUG)) { + || !(shouldLoadNative && loadPipewire(methodId, SCREENCAST_DEBUG))) { System.err.println( "Could not load native libraries for ScreencastHelper" @@ -98,7 +108,7 @@ return IS_NATIVE_LOADED; } - private static native boolean loadPipewire(boolean screencastDebug); + private static native boolean loadPipewire(int method, boolean isDebug); private static native int getRGBPixelsImpl( int x, int y, int width, int height, @@ -195,7 +205,7 @@ if (retVal >= 0) { // we have received a screen data return; - } else if (!checkReturnValue(retVal)) { + } else if (!checkReturnValue(retVal, true)) { return; } // else, try other tokens } @@ -209,25 +219,72 @@ null ); - checkReturnValue(retVal); + checkReturnValue(retVal, true); } - private static boolean checkReturnValue(int retVal) { + private static boolean checkReturnValue(int retVal, + boolean throwException) { if (retVal == DENIED) { - // user explicitly denied the capture, no more tries. - throw new SecurityException( - "Screen Capture in the selected area was not allowed" - ); + if (SCREENCAST_DEBUG) { + System.err.println("robot action: access denied by user."); + } + if (throwException) { + // user explicitly denied the capture, no more tries. + throw new SecurityException( + "Screen Capture in the selected area was not allowed" + ); + } } else if (retVal == ERROR) { if (SCREENCAST_DEBUG) { - System.err.println("Screen capture failed."); + System.err.println("robot action: failed."); } } else if (retVal == OUT_OF_BOUNDS) { if (SCREENCAST_DEBUG) { System.err.println( "Token does not provide access to requested area."); } + } else if (retVal == NO_STREAMS) { + if (SCREENCAST_DEBUG) { + System.err.println("robot action: no streams available"); + } } return retVal != ERROR; } + + private static void performWithToken(Function func) { + if (!XdgDesktopPortal.isRemoteDesktop() || !IS_NATIVE_LOADED) return; + + timerCloseSessionRestart(); + + for (TokenItem tokenItem : TokenStorage.getTokens(getSystemScreensBounds())) { + int retVal = func.apply(tokenItem.token); + + if (retVal >= 0 || !checkReturnValue(retVal, false)) { + return; + } + } + + checkReturnValue(func.apply(null), false); + } + + public static synchronized void remoteDesktopMouseMove(int x, int y) { + performWithToken((token) -> remoteDesktopMouseMoveImpl(x, y, token)); + } + + public static synchronized void remoteDesktopMouseButton(boolean isPress, int buttons) { + performWithToken((token) -> remoteDesktopMouseButtonImpl(isPress, buttons, token)); + } + + public static synchronized void remoteDesktopMouseWheel(int wheel) { + performWithToken((token) -> remoteDesktopMouseWheelImpl(wheel, token)); + } + + public static synchronized void remoteDesktopKey(boolean isPress, int key) { + performWithToken((token) -> remoteDesktopKeyImpl(isPress, key, token)); + } + + private static synchronized native int remoteDesktopMouseMoveImpl(int x, int y, String token); + private static synchronized native int remoteDesktopMouseButtonImpl(boolean isPress, int buttons, String token); + private static synchronized native int remoteDesktopMouseWheelImpl(int wheelAmt, String token); + private static synchronized native int remoteDesktopKeyImpl(boolean isPress, int key, String token); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java --- openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -69,6 +69,9 @@ private static final String REL_NAME_SECONDARY = ".awt/robot/screencast-tokens.properties"; + private static final String REL_RD_NAME = + ".java/robot/remote-desktop-tokens.properties"; + private static final Properties PROPS = new Properties(); private static final Path PROPS_PATH; private static final Path PROP_FILENAME; @@ -107,11 +110,18 @@ return null; } - Path path = Path.of(userHome, REL_NAME); - Path secondaryPath = Path.of(userHome, REL_NAME_SECONDARY); + Path path; + Path secondaryPath = null; + + if (XdgDesktopPortal.isRemoteDesktop()) { + path = Path.of(userHome, REL_RD_NAME); + } else { + path = Path.of(userHome, REL_NAME); + secondaryPath = Path.of(userHome, REL_NAME_SECONDARY); + } boolean copyFromSecondary = !Files.isWritable(path) - && Files.isWritable(secondaryPath); + && secondaryPath != null && Files.isWritable(secondaryPath); Path workdir = path.getParent(); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/screencast/XdgDesktopPortal.java openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/XdgDesktopPortal.java --- openjdk-21-21.0.8+9/src/java.desktop/unix/classes/sun/awt/screencast/XdgDesktopPortal.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/classes/sun/awt/screencast/XdgDesktopPortal.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025, 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. 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 sun.awt.screencast; + +import sun.awt.SunToolkit; +import sun.awt.UNIXToolkit; + +import java.awt.Toolkit; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; + +public class XdgDesktopPortal { + private static final String METHOD_X11 = "x11"; + private static final String METHOD_SCREENCAST = "dbusScreencast"; + private static final String METHOD_REMOTE_DESKTOP = "dbusRemoteDesktop"; + + private static final String method; + private static final boolean isRemoteDesktop; + private static final boolean isScreencast; + + private XdgDesktopPortal() {} + + static { + boolean isOnWayland = false; + + if (Toolkit.getDefaultToolkit() instanceof SunToolkit sunToolkit) { + isOnWayland = sunToolkit.isRunningOnWayland(); + } + + String defaultMethod = METHOD_X11; + if (isOnWayland) { + Integer gnomeShellVersion = null; + + UNIXToolkit toolkit = (UNIXToolkit) Toolkit.getDefaultToolkit(); + if ("gnome".equals(toolkit.getDesktop())) { + gnomeShellVersion = toolkit.getGnomeShellMajorVersion(); + } + + defaultMethod = (gnomeShellVersion != null && gnomeShellVersion >= 47) + ? METHOD_REMOTE_DESKTOP + : METHOD_SCREENCAST; + } + + @SuppressWarnings("removal") + String m = AccessController.doPrivileged( + new GetPropertyAction( + "awt.robot.screenshotMethod", defaultMethod + )); + + if (!METHOD_REMOTE_DESKTOP.equals(m) + && !METHOD_SCREENCAST.equals(m) + && !METHOD_X11.equals(m)) { + m = defaultMethod; + } + + isRemoteDesktop = METHOD_REMOTE_DESKTOP.equals(m); + isScreencast = METHOD_SCREENCAST.equals(m); + method = m; + + } + + public static String getMethod() { + return method; + } + + public static boolean isRemoteDesktop() { + return isRemoteDesktop; + } + + public static boolean isScreencast() { + return isScreencast; + } +} diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h openjdk-21-21.0.9+10/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h 2025-10-13 07:49:24.000000000 +0000 @@ -62,4 +62,11 @@ jfieldID bitsPerPixel; }; +#define MAX_DISPLAY_MODES 256 +typedef struct { + unsigned int width; + unsigned int height; + jint refresh; +} DisplayMode; + #endif /* _AWT_GRAPHICSENV_H_ */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2025-10-13 07:49:24.000000000 +0000 @@ -55,6 +55,7 @@ #include "gdefs.h" #include #include "Trace.h" +#include int awt_numScreens; /* Xinerama-aware number of screens */ @@ -76,6 +77,8 @@ jmethodID awtNotifyAllMID = NULL; jboolean awtLockInited = JNI_FALSE; +static Bool useNewConfigDisplayMode = True; + /** Convenience macro for loading the lock-related method IDs. */ #define GET_STATIC_METHOD(klass, method_id, method_name, method_sig) \ do { \ @@ -1508,6 +1511,20 @@ typedef void (*XRRFreeCrtcInfoType)(XRRCrtcInfo *crtcInfo); +typedef void (*XRRSetScreenSizeType)(Display *dpy, Window window, + int width, int height, + int mmWidth, int mmHeight); + +typedef Status (*XRRSetCrtcConfigType)(Display *dpy, + XRRScreenResources *resources, + RRCrtc crtc, + Time timestamp, + int x, int y, + RRMode mode, + Rotation rotation, + RROutput *outputs, + int noutputs); + static XRRQueryVersionType awt_XRRQueryVersion; static XRRGetScreenInfoType awt_XRRGetScreenInfo; static XRRFreeScreenConfigInfoType awt_XRRFreeScreenConfigInfo; @@ -1523,6 +1540,8 @@ static XRRFreeOutputInfoType awt_XRRFreeOutputInfo; static XRRGetCrtcInfoType awt_XRRGetCrtcInfo; static XRRFreeCrtcInfoType awt_XRRFreeCrtcInfo; +static XRRSetScreenSizeType awt_XRRSetScreenSize; +static XRRSetCrtcConfigType awt_XRRSetCrtcConfig; #define LOAD_XRANDR_FUNC(f) \ do { \ @@ -1600,6 +1619,8 @@ LOAD_XRANDR_FUNC(XRRFreeOutputInfo); LOAD_XRANDR_FUNC(XRRGetCrtcInfo); LOAD_XRANDR_FUNC(XRRFreeCrtcInfo); + LOAD_XRANDR_FUNC(XRRSetScreenSize); + LOAD_XRANDR_FUNC(XRRSetCrtcConfig); return JNI_TRUE; } @@ -1700,11 +1721,11 @@ /* * Class: sun_awt_X11GraphicsDevice * Method: initXrandrExtension - * Signature: ()Z + * Signature: (Z)Z */ JNIEXPORT jboolean JNICALL Java_sun_awt_X11GraphicsDevice_initXrandrExtension - (JNIEnv *env, jclass x11gd) + (JNIEnv *env, jclass x11gd, jboolean useOldConfigDisplayMode) { #if defined(NO_XRANDR) return JNI_FALSE; @@ -1720,10 +1741,305 @@ } AWT_FLUSH_UNLOCK(); + useNewConfigDisplayMode = !useOldConfigDisplayMode; + return ret; #endif /* NO_XRANDR */ } +// --------------------------------------------------- +// display mode change via XRRSetCrtcConfig +// --------------------------------------------------- +#if !defined(NO_XRANDR) +static jint refreshRateFromModeInfo(const XRRModeInfo *modeInfo) { + if (!modeInfo->hTotal || !modeInfo->vTotal) { + return 0; + } + + double vTotal = modeInfo->vTotal; + + if (modeInfo->modeFlags & RR_Interlace) { + vTotal /= 2; + } + + if (modeInfo->modeFlags & RR_DoubleScan) { + vTotal *= 2; + } + + return (jint) round((double) modeInfo->dotClock / (vTotal * (double) modeInfo->hTotal)); +} + +static inline Bool isLandscapeOrientation(XRRCrtcInfo* info) { + if (!info) { + return True; + } + return info->rotation == RR_Rotate_0 || info->rotation == RR_Rotate_180; +} + +static Bool xrrGetInfoForScreen(XRRScreenResources *res, + int screen, + XRRCrtcInfo **outCrtcInfo, + XRROutputInfo **outOutputInfo) { + if (!res) { + return False; + } + + int screenX = 0; + int screenY = 0; + + if (usingXinerama) { + int nscreens = 0; + XineramaScreenInfo *screens = XineramaQueryScreens(awt_display, &nscreens); + + if (!screens) { + return False; + } + + if (screen >= nscreens) { + XFree(screens); + return False; + } + + XineramaScreenInfo xScreenInfo = screens[screen]; + + screenX = xScreenInfo.x_org; + screenY= xScreenInfo.y_org; + + XFree(screens); + } + + for (int i = 0; i < res->noutput; ++i) { + XRROutputInfo *output = awt_XRRGetOutputInfo(awt_display, res, res->outputs[i]); + if (!output) { + continue; + } + if (output->connection == RR_Connected && output->crtc) { + // output is connected and has an active mode + XRRCrtcInfo *crtcInfo = awt_XRRGetCrtcInfo(awt_display, res, output->crtc); + if (crtcInfo) { + if (crtcInfo->mode != None + && crtcInfo->x == screenX + && crtcInfo->y == screenY) { + if (outCrtcInfo) { + *outCrtcInfo = crtcInfo; + } else { + awt_XRRFreeCrtcInfo(crtcInfo); + } + if (outOutputInfo) { + *outOutputInfo = output; + } else { + awt_XRRFreeOutputInfo(output); + } + return True; + } + awt_XRRFreeCrtcInfo(crtcInfo); + } + } + awt_XRRFreeOutputInfo(output); + } + + return False; +} + +static jobject xrrGetCurrentDisplayMode(JNIEnv* env, int screen) { + XRRScreenResources *res = awt_XRRGetScreenResources(awt_display, DefaultRootWindow(awt_display)); + if (!res) { + return NULL; + } + + XRRCrtcInfo* currentCrtcInfo = NULL; + if (!xrrGetInfoForScreen(res, screen, ¤tCrtcInfo, NULL)) { + goto cleanup; + } + + if (!currentCrtcInfo || currentCrtcInfo->mode == None) { + goto cleanup; + } + + for (int i = 0; i < res->nmode; ++i) { + if (res->modes[i].id == currentCrtcInfo->mode) { + XRRModeInfo mode = res->modes[i]; + DisplayMode dm = { + mode.width, + mode.height, + refreshRateFromModeInfo(&mode) + }; + + Bool isLandscape = isLandscapeOrientation(currentCrtcInfo); + + jint resultWidth = isLandscape ? (jint) dm.width : (jint) dm.height; + jint resultHeight = isLandscape ? (jint) dm.height : (jint) dm.width; + + jobject displayMode = X11GD_CreateDisplayMode(env, + resultWidth, + resultHeight, + BIT_DEPTH_MULTI, + dm.refresh); + + awt_XRRFreeCrtcInfo(currentCrtcInfo); + awt_XRRFreeScreenResources(res); + + return displayMode; + } + } + + cleanup: + if (currentCrtcInfo) { + awt_XRRFreeCrtcInfo(currentCrtcInfo); + } + awt_XRRFreeScreenResources(res); + return NULL; +} + +static Bool isUniqueDisplayMode(DisplayMode seen[], int count, unsigned int width, unsigned int height, int refresh) { + for (int i = 0; i < count; ++i) { + if (seen[i].width == width && + seen[i].height == height && + seen[i].refresh == refresh) { + return False; + } + } + return True; +} + +static void xrrEnumDisplayModes(JNIEnv *env, jobject arrayList, jint screen) { + XRRScreenResources *res = awt_XRRGetScreenResources(awt_display, DefaultRootWindow(awt_display)); + if (!res) { + return; + } + + XRRCrtcInfo *crtcInfo = NULL; + XRROutputInfo *outputInfo = NULL; + if (!xrrGetInfoForScreen(res, screen, &crtcInfo, &outputInfo)) { + goto cleanup; + } + + DisplayMode seenModes[MAX_DISPLAY_MODES]; + int seenCount = 0; + + Bool isLandscape = isLandscapeOrientation(crtcInfo); + + for (int i = 0; i < outputInfo->nmode; ++i) { + RRMode mode_id = outputInfo->modes[i]; + + for (int j = 0; j < res->nmode; ++j) { + if (res->modes[j].id == mode_id) { + XRRModeInfo mode = res->modes[j]; + jint rr = refreshRateFromModeInfo(&mode); + + // The refresh rate is stored as an integer in Java, so we need to round the double value. + // Because of this rounding, duplicate modes may appear. We only keep the first one encountered. + if (isUniqueDisplayMode(seenModes, seenCount, mode.width, mode.height, rr)) { + seenModes[seenCount++] = (DisplayMode) { + mode.width, + mode.height, + rr + }; + X11GD_AddDisplayMode(env, arrayList, + isLandscape ? (jint) mode.width : (jint) mode.height, + isLandscape ? (jint) mode.height : (jint) mode.width, + BIT_DEPTH_MULTI, + rr); + if ((*env)->ExceptionCheck(env)) { + goto cleanup; + } + } + break; + } + } + } + + cleanup: + if (outputInfo) { + awt_XRRFreeOutputInfo(outputInfo); + } + if (crtcInfo) { + awt_XRRFreeCrtcInfo(crtcInfo); + } + awt_XRRFreeScreenResources(res); +} + +static void xrrChangeDisplayMode(jint screen, jint width, jint height, jint refreshRate) { + Drawable root = DefaultRootWindow(awt_display); + + + XRRScreenResources *res = awt_XRRGetScreenResources(awt_display, root); + if (!res) { + return; + } + + XRRCrtcInfo *crtcInfo = NULL; + XRROutputInfo *outputInfo = NULL; + + if (!xrrGetInfoForScreen(res, screen, &crtcInfo, &outputInfo)) { + goto cleanup; + } + + RRMode new_mode = None; + + Bool isLandscape = isLandscapeOrientation(crtcInfo); + + for (int i = 0; i < res->nmode; ++i) { + XRRModeInfo mode = res->modes[i]; + jint rr = refreshRateFromModeInfo(&mode); + + Bool matchW = (isLandscape ? mode.width : mode.height) == (unsigned int) width; + Bool matchH = (isLandscape ? mode.height : mode.width) == (unsigned int) height; + + if (matchW && matchH && rr == refreshRate) { + for (int j = 0; j < outputInfo->nmode; ++j) { + if (mode.id == outputInfo->modes[j]) { + // belongs to our output + new_mode = mode.id; + break; + } + } + if (new_mode != None) { + break; + } + } + } + + if (new_mode == None) { + goto cleanup; + } + + awt_XRRSetCrtcConfig (awt_display, res, outputInfo->crtc, CurrentTime, + 0, 0, None, RR_Rotate_0, NULL, 0); + + int resultMmWidth = outputInfo->mm_width + ? (int) outputInfo->mm_width + : DisplayWidthMM(awt_display, DefaultScreen(awt_display)); + + int resultMmHeight = outputInfo->mm_height + ? (int) outputInfo->mm_height + : XDisplayHeightMM(awt_display, DefaultScreen(awt_display)); + + awt_XRRSetScreenSize(awt_display, root, + width, height, + resultMmWidth, resultMmHeight); + + Status s = awt_XRRSetCrtcConfig(awt_display, res, outputInfo->crtc, + CurrentTime, + crtcInfo->x, crtcInfo->y, + new_mode, crtcInfo->rotation, + crtcInfo->outputs, crtcInfo->noutput); + + cleanup: + if (crtcInfo) { + awt_XRRFreeCrtcInfo(crtcInfo); + } + if (outputInfo) { + awt_XRRFreeOutputInfo(outputInfo); + } + awt_XRRFreeScreenResources(res); +} +#endif + +// --------------------------------------------------- +// display mode change via XRRSetCrtcConfig +// --------------------------------------------------- + /* * Class: sun_awt_X11GraphicsDevice * Method: getCurrentDisplayMode @@ -1736,9 +2052,17 @@ #if defined(NO_XRANDR) return NULL; #else - XRRScreenConfiguration *config; jobject displayMode = NULL; + if (useNewConfigDisplayMode) { + AWT_LOCK(); + displayMode = xrrGetCurrentDisplayMode(env, screen); + AWT_FLUSH_UNLOCK(); + return displayMode; + } + + XRRScreenConfiguration *config; + AWT_LOCK(); if (screen < ScreenCount(awt_display)) { @@ -1789,7 +2113,12 @@ { #if !defined(NO_XRANDR) - AWT_LOCK(); + if (useNewConfigDisplayMode) { + AWT_LOCK(); + xrrEnumDisplayModes(env, arrayList, screen); + AWT_FLUSH_UNLOCK(); + return; + } if (XScreenCount(awt_display) > 0) { @@ -1839,6 +2168,15 @@ jint screen, jint width, jint height, jint refreshRate) { #if !defined(NO_XRANDR) + if (useNewConfigDisplayMode) { + AWT_LOCK(); + XGrabServer(awt_display); + xrrChangeDisplayMode(screen, width, height, refreshRate); + XUngrabServer(awt_display); + AWT_FLUSH_UNLOCK(); + return; + } + jboolean success = JNI_FALSE; XRRScreenConfiguration *config; Drawable root; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c 2025-10-13 07:49:24.000000000 +0000 @@ -1618,14 +1618,14 @@ if (NULL != pX11IMData->statusWindow) { Window focus = 0; int revert_to; -#if defined(_LP64) && !defined(_LITTLE_ENDIAN) - // The Window value which is used for XGetICValues must be 32bit on BigEndian XOrg's xlib - unsigned int w = 0; -#else Window w = 0; -#endif XGetInputFocus(awt_display, &focus, &revert_to); XGetICValues(pX11IMData->current_ic, XNFocusWindow, &w, NULL); +#if defined(_LP64) && !defined(_LITTLE_ENDIAN) + // On 64bit BigEndian, + // Window value may be stored on high 32bit by XGetICValues via XIM + if (w > 0xffffffffUL) w = w >> 32; +#endif if (RevertToPointerRoot == revert_to && pX11IMData->ic_active != pX11IMData->ic_passive) { if (pX11IMData->current_ic == pX11IMData->ic_active) { @@ -1674,12 +1674,7 @@ { X11InputMethodData *pX11IMData = NULL; char * ret = NULL; -#if defined(__linux__) && defined(_LP64) && !defined(_LITTLE_ENDIAN) - // XIMPreeditState value which is used for XGetICValues must be 32bit on BigEndian XOrg's xlib - unsigned int state = XIMPreeditUnKnown; -#else XIMPreeditState state = XIMPreeditUnKnown; -#endif XVaNestedList pr_atrb; @@ -1695,6 +1690,11 @@ ret = XGetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL); XFree((void *)pr_atrb); AWT_UNLOCK(); +#if defined(__linux__) && defined(_LP64) && !defined(_LITTLE_ENDIAN) + // On 64bit BigEndian, + // XIMPreeditState value may be stored on high 32bit by XGetICValues via XIM + if (state > 0xffffffffUL) state = state >> 32; +#endif if ((ret != 0) && ((strcmp(ret, XNPreeditAttributes) == 0) diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -617,11 +617,14 @@ glib_version_2_68 = !fp_glib_check_version(2, 68, 0); if (glib_version_2_68) { + // those function are called only by Screencast / Remote desktop fp_g_string_replace = dl_symbol("g_string_replace"); //since: 2.68 fp_g_uuid_string_is_valid = //since: 2.52 dl_symbol("g_uuid_string_is_valid"); + fp_g_variant_print = dl_symbol("g_variant_print"); // since 2.24 } fp_g_string_printf = dl_symbol("g_string_printf"); + fp_g_strconcat = dl_symbol("g_strconcat"); fp_g_error_free = dl_symbol("g_error_free"); fp_g_unix_fd_list_get = dl_symbol("g_unix_fd_list_get"); @@ -3099,6 +3102,7 @@ gtk->g_variant_new_string = fp_g_variant_new_string; gtk->g_variant_new_boolean = fp_g_variant_new_boolean; gtk->g_variant_new_uint32 = fp_g_variant_new_uint32; + gtk->g_variant_print = fp_g_variant_print; gtk->g_variant_get = fp_g_variant_get; gtk->g_variant_get_string = fp_g_variant_get_string; @@ -3123,6 +3127,7 @@ gtk->g_string_free = fp_g_string_free; gtk->g_string_replace = fp_g_string_replace; gtk->g_string_printf = fp_g_string_printf; + gtk->g_strconcat = fp_g_strconcat; gtk->g_uuid_string_is_valid = fp_g_uuid_string_is_valid; gtk->g_main_context_iteration = fp_g_main_context_iteration; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -399,6 +399,7 @@ static gchar** (*fp_g_strsplit)(const gchar *string, const gchar *delimiter, gint max_tokens); static void (*fp_g_strfreev)(gchar **str_array); +static gchar* (*fp_g_strconcat)(const gchar* string1, ...); static cairo_surface_t* (*fp_cairo_image_surface_create)(cairo_format_t format, @@ -738,6 +739,8 @@ static GVariant *(*fp_g_variant_new_uint32)(guint32 value); +static gchar *(*fp_g_variant_print) (GVariant* value, gboolean type_annotate); + static void (*fp_g_variant_get)(GVariant *value, const gchar *format_string, ...); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -678,6 +678,7 @@ GVariant *(*g_variant_new_boolean)(gboolean value); GVariant *(*g_variant_new_uint32)(guint32 value); + gchar *(*g_variant_print)(GVariant* value, gboolean type_annotate); void (*g_variant_get)(GVariant *value, const gchar *format_string, @@ -734,6 +735,8 @@ const gchar *format, ...); + gchar* (*g_strconcat)(const gchar* string1, ...); + gboolean (*g_uuid_string_is_valid)(const gchar *str); diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -30,12 +30,17 @@ #include #include "jni_util.h" #include "awt.h" + +#ifndef _AIX #include "screencast_pipewire.h" #include "fp_pipewire.h" +#include "java_awt_event_KeyEvent.h" + #include #include "gtk_interface.h" #include "gtk3_interface.h" +#include "canvas.h" int DEBUG_SCREENCAST_ENABLED = FALSE; @@ -50,6 +55,7 @@ struct ScreenSpace screenSpace = {0}; static struct PwLoopData pw = {0}; volatile bool isGtkMainThread = FALSE; +gboolean isRemoteDesktop = FALSE; jclass tokenStorageClass = NULL; jmethodID storeTokenMethodID = NULL; @@ -140,7 +146,7 @@ /** * @return TRUE on success */ -static gboolean initScreencast(const gchar *token, +static gboolean initPortal(const gchar *token, GdkRectangle *affectedBounds, gint affectedBoundsLength) { gboolean isSameToken = !token @@ -167,8 +173,8 @@ if (!initScreenSpace() || !initXdgDesktopPortal() - || (pw.pwFd = getPipewireFd(token, - affectedBounds, + || !initAndStartSession(token, &pw.pwFd) + || (pw.pwFd = getPipewireFd(affectedBounds, affectedBoundsLength)) < 0) { doCleanup(); return FALSE; @@ -801,10 +807,19 @@ * Signature: (IZ)Z */ JNIEXPORT jboolean JNICALL Java_sun_awt_screencast_ScreencastHelper_loadPipewire( - JNIEnv *env, jclass cls, jboolean screencastDebug + JNIEnv *env, jclass cls, jint method, jboolean screencastDebug ) { DEBUG_SCREENCAST_ENABLED = screencastDebug; + if (method != XDG_METHOD_SCREENCAST + && method != XDG_METHOD_REMOTE_DESKTOP) { + return JNI_FALSE; + } + + isRemoteDesktop = method == XDG_METHOD_REMOTE_DESKTOP; + + DEBUG_SCREENCAST("method %d\n", method) + if (!loadSymbols()) { return JNI_FALSE; } @@ -877,7 +892,7 @@ GdkRectangle *affectedScreenBounds, gint affectedBoundsLength ) { - if (!initScreencast(token, affectedScreenBounds, affectedBoundsLength)) { + if (!initPortal(token, affectedScreenBounds, affectedBoundsLength)) { return pw.pwFd; } @@ -948,6 +963,7 @@ const gchar *token = jtoken ? (*env)->GetStringUTFChars(env, jtoken, NULL) : NULL; + JNU_CHECK_EXCEPTION_RETURN(env, RESULT_ERROR); isGtkMainThread = gtk->g_main_context_is_owner(gtk->g_main_context_default()); DEBUG_SCREENCAST( @@ -1040,3 +1056,192 @@ releaseToken(env, jtoken, token); return 0; } + +/* + * Class: sun_awt_screencast_ScreencastHelper + * Method: remoteDesktopMouseMove + * Signature: (IILjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_remoteDesktopMouseMoveImpl + (JNIEnv *env, jclass cls, jint jx, jint jy, jstring jtoken) { + + + const gchar *token = jtoken + ? (*env)->GetStringUTFChars(env, jtoken, NULL) + : NULL; + JNU_CHECK_EXCEPTION_RETURN(env, RESULT_ERROR); + + DEBUG_SCREENCAST("moving mouse to\n\t%d %d\n\twith token |%s|\n", jx, jy, token); + + gboolean result = initPortal(token, NULL, 0); + DEBUG_SCREENCAST("init result %b, moving to %d %d\n", result, jx, jy) + + if (result) { + if (!remoteDesktopMouseMove(jx, jy)) { + releaseToken(env, jtoken, token); + return RESULT_DENIED; + } + } + + releaseToken(env, jtoken, token); + + return result ? RESULT_OK : pw.pwFd; +} + +/* + * Class: sun_awt_screencast_ScreencastHelper + * Method: remoteDesktopMouseButtonImpl + * Signature: (ZILjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_remoteDesktopMouseButtonImpl + (JNIEnv *env, jclass cls, jboolean isPress, jint buttons, jstring jtoken) { + + const gchar *token = jtoken + ? (*env)->GetStringUTFChars(env, jtoken, NULL) + : NULL; + JNU_CHECK_EXCEPTION_RETURN(env, RESULT_ERROR); + + gboolean result = initPortal(token, NULL, 0); + DEBUG_SCREENCAST("init result %b, mouse pressing %d\n", result, buttons) + + if (result) { + if (!remoteDesktopMouse(isPress, buttons)) { + releaseToken(env, jtoken, token); + return RESULT_DENIED; + } + } + + releaseToken(env, jtoken, token); + + return result ? RESULT_OK : pw.pwFd; +} + +/* + * Class: sun_awt_screencast_ScreencastHelper + * Method: remoteDesktopMouseWheelImpl + * Signature: (ILjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_remoteDesktopMouseWheelImpl + (JNIEnv *env, jclass cls, jint jWheelAmt, jstring jtoken) { + + const gchar *token = jtoken + ? (*env)->GetStringUTFChars(env, jtoken, NULL) + : NULL; + JNU_CHECK_EXCEPTION_RETURN(env, RESULT_ERROR); + + gboolean result = initPortal(token, NULL, 0); + DEBUG_SCREENCAST("init result %b, mouse wheel %d\n", result, jWheelAmt) + + if (result) { + if (!remoteDesktopMouseWheel(jWheelAmt)) { + releaseToken(env, jtoken, token); + return RESULT_DENIED; + } + } + + releaseToken(env, jtoken, token); + + return result ? RESULT_OK : pw.pwFd; +} + +static int getNumpadKey(jint jkey) { + switch (jkey) { + case java_awt_event_KeyEvent_VK_NUMPAD0: return XK_KP_Insert; + case java_awt_event_KeyEvent_VK_NUMPAD1: return XK_KP_End; + case java_awt_event_KeyEvent_VK_NUMPAD2: return XK_KP_Down; + case java_awt_event_KeyEvent_VK_NUMPAD3: return XK_KP_Page_Down; + case java_awt_event_KeyEvent_VK_NUMPAD4: return XK_KP_Left; + case java_awt_event_KeyEvent_VK_NUMPAD5: return XK_KP_Begin; + case java_awt_event_KeyEvent_VK_NUMPAD6: return XK_KP_Right; + case java_awt_event_KeyEvent_VK_NUMPAD7: return XK_KP_Home; + case java_awt_event_KeyEvent_VK_NUMPAD8: return XK_KP_Up; + case java_awt_event_KeyEvent_VK_NUMPAD9: return XK_KP_Prior; + case java_awt_event_KeyEvent_VK_DECIMAL: + case java_awt_event_KeyEvent_VK_SEPARATOR: return XK_KP_Delete; + default: return 0; + } +} + +/* + * Class: sun_awt_screencast_ScreencastHelper + * Method: remoteDesktopKeyImpl + * Signature: (ZILjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_remoteDesktopKeyImpl + (JNIEnv *env, jclass cls, jboolean isPress, jint jkey, jstring jtoken) { + + int key = getNumpadKey(jkey); + if (!key) { + AWT_LOCK(); + key = awt_getX11KeySym(jkey); + AWT_UNLOCK(); + } + + if (key == NoSymbol || (*env)->ExceptionCheck(env)) { + return RESULT_ERROR; + } + + const gchar *token = jtoken + ? (*env)->GetStringUTFChars(env, jtoken, NULL) + : NULL; + JNU_CHECK_EXCEPTION_RETURN(env, RESULT_ERROR); + + gboolean result = initPortal(token, NULL, 0); + DEBUG_SCREENCAST("init result %b, key %d -> %d isPress %b\n", result, jkey, key, isPress) + + if (result) { + if (!remoteDesktopKey(isPress, key)) { + releaseToken(env, jtoken, token); + return RESULT_DENIED; + } + } + + releaseToken(env, jtoken, token); + + return result ? RESULT_OK : pw.pwFd; +} + +#else +JNIEXPORT void JNICALL +Java_sun_awt_screencast_ScreencastHelper_closeSession(JNIEnv *env, jclass cls) {} + +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl( + JNIEnv *env, + jclass cls, + jint jx, + jint jy, + jint jwidth, + jint jheight, + jintArray pixelArray, + jintArray affectedScreensBoundsArray, + jstring jtoken +) { + return -1; /* RESULT_ERROR */ +} + +JNIEXPORT jboolean JNICALL Java_sun_awt_screencast_ScreencastHelper_loadPipewire( + JNIEnv *env, jclass cls, jint method, jboolean screencastDebug +) { + return JNI_FALSE; +} + +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_remoteDesktopMouseMoveImpl + (JNIEnv *env, jclass cls, jint jx, jint jy, jstring token) { + return -1; +} + +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_remoteDesktopMouseButtonImpl + (JNIEnv *env, jclass cls, jboolean isPress, jint buttons, jstring jtoken) { + return -1; +} + +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_remoteDesktopMouseWheelImpl + (JNIEnv *env, jclass cls, jint jWheelAmt, jstring jtoken) { + return -1; +} + +JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_remoteDesktopKeyImpl + (JNIEnv *env, jclass cls, jboolean isPress, jint jkey, jstring jtoken) { + return -1; +} +#endif diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -41,6 +41,8 @@ void storeRestoreToken(const gchar* oldToken, const gchar* newToken); +void print_gvariant_content(gchar *caption, GVariant *response); + struct ScreenProps { guint32 id; GdkRectangle bounds; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -24,19 +24,26 @@ */ #include "stdlib.h" -#include -#include #include -#include -#include + +#include "java_awt_event_InputEvent.h" + +#ifndef _AIX #include "screencast_pipewire.h" + #include "screencast_portal.h" extern volatile bool isGtkMainThread; +extern gboolean isRemoteDesktop; extern struct ScreenSpace screenSpace; struct XdgDesktopPortalApi *portal = NULL; +extern int DEBUG_SCREENCAST_ENABLED; + +GDBusProxy *getProxy() { + return isRemoteDesktop ? portal->remoteDesktopProxy : portal->screenCastProxy; +} void errHandle( GError *error, @@ -167,26 +174,38 @@ } /** - * Checks screencast protocol version - * @return FALSE if version < 4, or could not be determined + * Checks the version of the Screencast/Remote Desktop protocol + * to determine whether it supports the restore_token. + * @return FALSE if version is below required, or could not be determined */ gboolean checkVersion() { static guint32 version = 0; + + const gchar *interface = isRemoteDesktop + ? PORTAL_IFACE_REMOTE_DESKTOP + : PORTAL_IFACE_SCREENCAST; + if (version == 0) { GError *error = NULL; + GVariant *retVersion = gtk->g_dbus_proxy_call_sync( - portal->screenCastProxy, + getProxy(), "org.freedesktop.DBus.Properties.Get", gtk->g_variant_new("(ss)", - "org.freedesktop.portal.ScreenCast", + interface, "version"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL ); + if (isRemoteDesktop) { + print_gvariant_content("checkVersion Remote Desktop", retVersion); + } else { + print_gvariant_content("checkVersion ScreenCast", retVersion); + } + if (!retVersion) { //no backend on system - DEBUG_SCREENCAST("!!! could not detect the screencast version\n", - NULL); + DEBUG_SCREENCAST("!!! could not detect the %s version\n", interface); return FALSE; } @@ -197,8 +216,7 @@ if (!varVersion){ gtk->g_variant_unref(retVersion); - DEBUG_SCREENCAST("!!! could not get the screencast version\n", - NULL); + DEBUG_SCREENCAST("!!! could not get the %s version\n", interface); return FALSE; } @@ -209,16 +227,22 @@ } - DEBUG_SCREENCAST("ScreenCast protocol version %d\n", version); - if (version < 4) { - DEBUG_SCREENCAST("!!! ScreenCast protocol version %d < 4," + gboolean isVersionOk = isRemoteDesktop + ? version >= PORTAL_MIN_VERSION_REMOTE_DESKTOP + : version >= PORTAL_MIN_VERSION_SCREENCAST; + + if (!isVersionOk) { + DEBUG_SCREENCAST("!!! %s protocol version %d < %d," " session restore is not available\n", - version); + interface, + version, + isRemoteDesktop + ? PORTAL_MIN_VERSION_REMOTE_DESKTOP + : PORTAL_MIN_VERSION_SCREENCAST + ); } - // restore_token was added in version 4, without it, - // user confirmation is required for every screenshot. - return version >= 4; + return isVersionOk; } /** @@ -263,9 +287,9 @@ portal->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, - "org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.ScreenCast", + PORTAL_DESKTOP_BUS_NAME, + PORTAL_DESKTOP_OBJECT_PATH, + PORTAL_IFACE_SCREENCAST, NULL, &err ); @@ -274,6 +298,29 @@ DEBUG_SCREENCAST("Failed to get ScreenCast portal: %s", err->message); ERR_HANDLE(err); return FALSE; + } else { + DEBUG_SCREENCAST("%s: connection/sender name %s / %s\n", + "ScreenCast", name, + portal->senderName); + } + + if (isRemoteDesktop) { + portal->remoteDesktopProxy = gtk->g_dbus_proxy_new_sync( + portal->connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + PORTAL_DESKTOP_BUS_NAME, + PORTAL_DESKTOP_OBJECT_PATH, + PORTAL_IFACE_REMOTE_DESKTOP, + NULL, + &err + ); + + if (err) { + DEBUG_SCREENCAST("Failed to get Remote Desktop portal: %s", err->message); + ERR_HANDLE(err); + return FALSE; + } } return checkVersion(); @@ -334,8 +381,8 @@ ) { helper->id = gtk->g_dbus_connection_signal_subscribe( portal->connection, - "org.freedesktop.portal.Desktop", - "org.freedesktop.portal.Request", + PORTAL_DESKTOP_BUS_NAME, + PORTAL_IFACE_REQUEST, "Response", path, NULL, @@ -380,7 +427,8 @@ if (status != 0) { DEBUG_SCREENCAST("Failed to create ScreenCast: %u\n", status); } else { - gtk->g_variant_lookup(result, "session_handle", "s", helper->data); + gboolean returned = gtk->g_variant_lookup(result, "session_handle", "s", helper->data); + DEBUG_SCREENCAST("session_handle returned %b %p\n", returned, helper->data) } helper->isDone = TRUE; @@ -427,6 +475,9 @@ gtk->g_variant_new_string(requestToken) ); + + DEBUG_SCREENCAST("sessionToken %s \n", sessionToken) + gtk->g_variant_builder_add( &builder, "{sv}", @@ -434,8 +485,14 @@ gtk->g_variant_new_string(sessionToken) ); + DEBUG_SCREENCAST("portalScreenCastCreateSession: proxy %s %p (rd: %p / sc: %p)\n", + isRemoteDesktop ? "remoteDesktop" : "screencast", + getProxy(), + portal->remoteDesktopProxy, + portal->screenCastProxy); + GVariant *response = gtk->g_dbus_proxy_call_sync( - portal->screenCastProxy, + getProxy(), "CreateSession", gtk->g_variant_new("(a{sv})", &builder), G_DBUS_CALL_FLAGS_NONE, @@ -444,6 +501,8 @@ &err ); + print_gvariant_content("CreateSession", response); + if (err) { DEBUG_SCREENCAST("Failed to create ScreenCast session: %s\n", err->message); @@ -452,6 +511,8 @@ waitForCallback(&helper); } + DEBUG_SCREENCAST("portal->screenCastSessionHandle %s\n", portal->screenCastSessionHandle); + unregisterScreenCastCallback(&helper); if (response) { gtk->g_variant_unref(response); @@ -497,6 +558,39 @@ callbackEnd(); } +static void callbackRemoteDesktopSelectDevices( + GDBusConnection *connection, + const char *senderName, + const char *objectPath, + const char *interfaceName, + const char *signalName, + GVariant *parameters, + void *data +) { + struct DBusCallbackHelper *helper = data; + + helper->data = (void *) 0; + + uint32_t status; + GVariant* result = NULL; + + gtk->g_variant_get(parameters, "(u@a{sv})", &status, &result); + + if (status != 0) { + DEBUG_SCREENCAST("Failed select devices: %u\n", status); + } else { + helper->data = (void *) 1; + } + + helper->isDone = TRUE; + + if (result) { + gtk->g_variant_unref(result); + } + + callbackEnd(); +} + gboolean portalScreenCastSelectSources(const gchar *token) { GError* err = NULL; @@ -542,25 +636,33 @@ gtk->g_variant_new_uint32(1) ); + // In the case of Remote Desktop, + // we add the restore_token and persist_mode to the SelectDevices call. + // 0: Do not persist (default) // 1: Permissions persist as long as the application is running // 2: Permissions persist until explicitly revoked - gtk->g_variant_builder_add( - &builder, - "{sv}", - "persist_mode", - gtk->g_variant_new_uint32(2) - ); - - if (validateToken(token)) { + if (!isRemoteDesktop) { gtk->g_variant_builder_add( &builder, "{sv}", - "restore_token", - gtk->g_variant_new_string(token) + "persist_mode", + gtk->g_variant_new_uint32(2) ); } + if (!isRemoteDesktop) { + if (validateToken(token)) { + DEBUG_SCREENCAST(">>> adding token %s\n", token); + gtk->g_variant_builder_add( + &builder, + "{sv}", + "restore_token", + gtk->g_variant_new_string(token) + ); + } + } + GVariant *response = gtk->g_dbus_proxy_call_sync( portal->screenCastProxy, "SelectSources", @@ -571,6 +673,8 @@ &err ); + print_gvariant_content("SelectSources", response); + if (err) { DEBUG_SCREENCAST("Failed to call SelectSources: %s\n", err->message); ERR_HANDLE(err); @@ -621,6 +725,15 @@ G_VARIANT_TYPE_ARRAY ); + print_gvariant_content("Streams", streams); + + if (!streams) { + DEBUG_SCREENCAST("No streams available with current token\n", NULL); + startHelper->result = RESULT_NO_STREAMS; + helper->isDone = TRUE; + return; + } + GVariantIter iter; gtk->g_variant_iter_init( &iter, @@ -658,9 +771,7 @@ helper->isDone = TRUE; - if (streams) { - gtk->g_variant_unref(streams); - } + gtk->g_variant_unref(streams); callbackEnd(); } @@ -703,7 +814,7 @@ ); GVariant *response = gtk->g_dbus_proxy_call_sync( - portal->screenCastProxy, + getProxy(), "Start", gtk->g_variant_new("(osa{sv})", portal->screenCastSessionHandle, "", &builder), G_DBUS_CALL_FLAGS_NONE, @@ -712,6 +823,8 @@ &err ); + print_gvariant_content("Start", response); + if (err) { DEBUG_SCREENCAST("Failed to start session: %s\n", err->message); ERR_HANDLE(err); @@ -805,9 +918,9 @@ if (portal->screenCastSessionHandle) { gtk->g_dbus_connection_call_sync( portal->connection, - "org.freedesktop.portal.Desktop", + PORTAL_DESKTOP_BUS_NAME, portal->screenCastSessionHandle, - "org.freedesktop.portal.Session", + PORTAL_IFACE_SESSION, "Close", NULL, NULL, @@ -886,33 +999,140 @@ return true; } +gboolean remoteDesktopSelectDevicesIfNeeded(const gchar* token) { + if (!isRemoteDesktop || !portal->remoteDesktopProxy) { + DEBUG_SCREENCAST("Skipping, remote desktop is not selected \n", NULL); + return TRUE; + } + + GError* err = NULL; + + gchar *requestPath = NULL; + gchar *requestToken = NULL; + + struct DBusCallbackHelper helper = {0}; + + + updateRequestPath( + &requestPath, + &requestToken + ); + + registerScreenCastCallback( + requestPath, + &helper, + callbackRemoteDesktopSelectDevices + ); + + GVariantBuilder builder; + + gtk->g_variant_builder_init( + &builder, + G_VARIANT_TYPE_VARDICT + ); + + gtk->g_variant_builder_add( + &builder, + "{sv}", "handle_token", + gtk->g_variant_new_string(requestToken) + ); + + // 1: KEYBOARD + // 2: POINTER + // 4: TOUCHSCREEN + gtk->g_variant_builder_add( + &builder, "{sv}", "types", + gtk->g_variant_new_uint32(1 | 2) + ); + + // 0: Do not persist (default) + // 1: Permissions persist as long as the application is running + // 2: Permissions persist until explicitly revoked + gtk->g_variant_builder_add( + &builder, + "{sv}", + "persist_mode", + gtk->g_variant_new_uint32(2) + ); + + if (validateToken(token)) { + gtk->g_variant_builder_add( + &builder, + "{sv}", + "restore_token", + gtk->g_variant_new_string(token) + ); + } + + GVariant *response = gtk->g_dbus_proxy_call_sync( + portal->remoteDesktopProxy, + "SelectDevices", + gtk->g_variant_new("(oa{sv})", portal->screenCastSessionHandle, &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &err + ); + + print_gvariant_content("SelectDevices", response); + + if (err) { + DEBUG_SCREENCAST("Failed to call SelectDevices: %s\n", err->message); + ERR_HANDLE(err); + } else { + waitForCallback(&helper); + } + + unregisterScreenCastCallback(&helper); + if (response) { + gtk->g_variant_unref(response); + } + + free(requestPath); + free(requestToken); + + return helper.data != NULL; +} + +gboolean initAndStartSession(const gchar *token, int *retVal) { + + *retVal = RESULT_ERROR; -int getPipewireFd(const gchar *token, - GdkRectangle *affectedBounds, - gint affectedBoundsLength) { if (!portalScreenCastCreateSession()) { DEBUG_SCREENCAST("Failed to create ScreenCast session\n", NULL); - return RESULT_ERROR; + return FALSE; } if (!portalScreenCastSelectSources(token)) { DEBUG_SCREENCAST("Failed to select sources\n", NULL); - return RESULT_ERROR; + return FALSE; + } + + if (!remoteDesktopSelectDevicesIfNeeded(token)) { + return FALSE; } ScreenCastResult startResult = portalScreenCastStart(token); DEBUG_SCREENCAST("portalScreenCastStart result |%i|\n", startResult); + if (startResult != RESULT_OK) { - DEBUG_SCREENCAST("Failed to start\n", NULL); - return startResult; - } else { - if (!checkCanCaptureAllRequiredScreens(affectedBounds, - affectedBoundsLength)) { - DEBUG_SCREENCAST("The location of the screens has changed, " - "the capture area is outside the allowed " - "area.\n", NULL) - return RESULT_OUT_OF_BOUNDS; - } + DEBUG_SCREENCAST("Failed to start %d\n", startResult); + *retVal = startResult; + return FALSE; + } + + *retVal = RESULT_OK; + return TRUE; +} + +int getPipewireFd(GdkRectangle *affectedBounds, + gint affectedBoundsLength) { + if (!checkCanCaptureAllRequiredScreens(affectedBounds, + affectedBoundsLength)) { + DEBUG_SCREENCAST("The location of the screens has changed, " + "the capture area is outside the allowed " + "area.\n", NULL) + return RESULT_OUT_OF_BOUNDS; } DEBUG_SCREENCAST("--- portalScreenCastStart\n", NULL); @@ -925,3 +1145,182 @@ DEBUG_SCREENCAST("pwFd %i\n", pipewireFd); return pipewireFd; } + + +void print_gvariant_content(gchar *caption, GVariant *response) { + if (!DEBUG_SCREENCAST_ENABLED) { + return; + } + + gchar *str = NULL; + if (response != NULL) { + str = gtk->g_variant_print(response, TRUE); + } + + DEBUG_SCREENCAST("%s response:\n\t%s\n", + caption, str); + + gtk->g_free(str); +} + +static gboolean callRemoteDesktop(const gchar* methodName, GVariant *params) { + GError *err = NULL; + GVariantBuilder builder; + gtk->g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + + GVariant *response = gtk->g_dbus_proxy_call_sync( + portal->remoteDesktopProxy, + methodName, + params, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &err + ); + + gchar * caption = gtk->g_strconcat("callRemoteDesktop ", methodName, NULL); + print_gvariant_content(caption, response); + gtk->g_free(caption); + + DEBUG_SCREENCAST("%s: response %p err %p\n", methodName, response, err); + + if (err) { + DEBUG_SCREENCAST("Failed to call %s: %s\n", methodName, err->message); + ERR_HANDLE(err); + + // e.g. user denied mouse keyboard/interaction + return FALSE; + } + + return TRUE; +} + +void clampCoordsIfNeeded(int *x, int *y) { + if (screenSpace.screenCount <= 0 || x == NULL || y == NULL) { + return; + } + + GdkRectangle s0 = screenSpace.screens[0].bounds; + int minX = s0.x; + int minY = s0.y; + int maxX = s0.x + s0.width; + int maxY = s0.y + s0.height; + + for (int i = 1; i < screenSpace.screenCount; ++i) { + GdkRectangle s = screenSpace.screens[i].bounds; + if (s.x < minX) minX = s.x; + if (s.y < minY) minY = s.y; + if (s.x + s.width > maxX) maxX = s.x + s.width; + if (s.y + s.height > maxY) maxY = s.y + s.height; + } + + if (*x < minX) { + *x = minX; + } else if (*x > maxX) { + *x = maxX - 1; + } + + if (*y < minY) { + *y = minY; + } else if (*y > maxY) { + *y = maxY - 1; + } +} + +gboolean remoteDesktopMouseMove(int x, int y) { + guint32 streamId = 0; + int relX = -1; + int relY = -1; + + DEBUG_SCREENCAST("mouseMove %d %d\n", x, y); + clampCoordsIfNeeded(&x, &y); + DEBUG_SCREENCAST("after clamping %d %d\n", x, y); + + for (int i = 0; i < screenSpace.screenCount; ++i) { + struct ScreenProps *screenProps = &screenSpace.screens[i]; + GdkRectangle rect = screenProps->bounds; + + if (x >= rect.x && + y >= rect.y && + x < rect.x + rect.width && + y < rect.y + rect.height) { + streamId = screenProps->id; + relX = x - rect.x; + relY = y - rect.y; + + DEBUG_SCREENCAST("screenId#%i point %dx%d (rel %i %i) inside of screen (%d, %d, %d, %d)\n", + streamId, + x, y, relX, relY, + rect.x, rect.y, rect.width, rect.height); + + break; + } + } + + if (streamId == 0) { + DEBUG_SCREENCAST("outside of available screens\n", NULL); + return TRUE; + } + + GVariantBuilder builder; + gtk->g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + GVariant *params = gtk->g_variant_new("(oa{sv}udd)", portal->screenCastSessionHandle, &builder, + streamId, (double) relX, (double) relY); + return callRemoteDesktop("NotifyPointerMotionAbsolute", params); +} + +gboolean callRemoteDesktopNotifyPointerButton(gboolean isPress, int evdevButton) { + DEBUG_SCREENCAST("isPress %d evdevButton %d\n", isPress, evdevButton); + + GVariantBuilder builder; + gtk->g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + GVariant *params = gtk->g_variant_new("(oa{sv}iu)", + portal->screenCastSessionHandle, &builder, evdevButton, isPress); + return callRemoteDesktop("NotifyPointerButton", params); +} + +gboolean remoteDesktopMouse(gboolean isPress, int buttons) { + DEBUG_SCREENCAST("isPress %d awt buttons mask %d\n", isPress, buttons); + + if (buttons & java_awt_event_InputEvent_BUTTON1_MASK + || buttons & java_awt_event_InputEvent_BUTTON1_DOWN_MASK) { + if (!callRemoteDesktopNotifyPointerButton(isPress, 0x110)) { // BTN_LEFT + return FALSE; + } + } + if (buttons & java_awt_event_InputEvent_BUTTON2_MASK + || buttons & java_awt_event_InputEvent_BUTTON2_DOWN_MASK) { + if (!callRemoteDesktopNotifyPointerButton(isPress, 0x112)) { // BTN_MIDDLE + return FALSE; + } + + } + if (buttons & java_awt_event_InputEvent_BUTTON3_MASK + || buttons & java_awt_event_InputEvent_BUTTON3_DOWN_MASK) { + if (!callRemoteDesktopNotifyPointerButton(isPress, 0x111)) { // BTN_RIGHT + return FALSE; + } + } + + return TRUE; +} + +gboolean remoteDesktopMouseWheel(int wheelAmt) { + DEBUG_SCREENCAST("MouseWheel %d\n", wheelAmt); + + GVariantBuilder builder; + gtk->g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + GVariant *params = gtk->g_variant_new("(oa{sv}ui)", portal->screenCastSessionHandle, &builder, 0, wheelAmt); + return callRemoteDesktop("NotifyPointerAxisDiscrete", params); +} + +gboolean remoteDesktopKey(gboolean isPress, int key) { + DEBUG_SCREENCAST("Key%s key %d -> \n", isPress ? "Press" : "Release", key); + + GVariantBuilder builder; + gtk->g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + GVariant *params = gtk->g_variant_new ("(oa{sv}iu)", portal->screenCastSessionHandle, &builder, key, isPress); + return callRemoteDesktop("NotifyKeyboardKeysym", params); +} + +#endif diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.h openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.h --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.h 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -36,11 +36,21 @@ #define PORTAL_REQUEST_TEMPLATE "/org/freedesktop/portal/desktop/" \ "request/%s/awtPipewire%lu" +#define PORTAL_DESKTOP_BUS_NAME "org.freedesktop.portal.Desktop" +#define PORTAL_DESKTOP_OBJECT_PATH "/org/freedesktop/portal/desktop" + +#define PORTAL_IFACE_REQUEST "org.freedesktop.portal.Request" +#define PORTAL_IFACE_SESSION "org.freedesktop.portal.Session" +#define PORTAL_IFACE_SCREENCAST "org.freedesktop.portal.ScreenCast" +#define PORTAL_IFACE_REMOTE_DESKTOP "org.freedesktop.portal.RemoteDesktop" + +#define PORTAL_MIN_VERSION_SCREENCAST 4 +#define PORTAL_MIN_VERSION_REMOTE_DESKTOP 2 + void debug_screencast(const char *__restrict fmt, ...); -int getPipewireFd(const gchar *token, - GdkRectangle *affectedBounds, - gint affectedBoundsLength); +gboolean initAndStartSession(const gchar *token, int *retVal); +int getPipewireFd(GdkRectangle *affectedBounds, gint affectedBoundsLength); void portalScreenCastCleanup(); @@ -48,8 +58,14 @@ void errHandle(GError *error, const gchar *functionName, int lineNum); +gboolean remoteDesktopMouseMove(int x, int y); +gboolean remoteDesktopMouseWheel(int wheelAmt); +gboolean remoteDesktopMouse(gboolean isPress, int buttons); +gboolean remoteDesktopKey(gboolean isPress, int key); + struct XdgDesktopPortalApi { GDBusConnection *connection; + GDBusProxy *remoteDesktopProxy; GDBusProxy *screenCastProxy; gchar *senderName; char *screenCastSessionHandle; @@ -66,8 +82,15 @@ RESULT_ERROR = -1, RESULT_DENIED = -11, RESULT_OUT_OF_BOUNDS = -12, + RESULT_NO_STREAMS = -13, } ScreenCastResult; +typedef enum { + XDG_METHOD_SCREENCAST = 0, + XDG_METHOD_REMOTE_DESKTOP = 1, +} XdgPortalMethod; + + struct StartHelper { const gchar *token; ScreenCastResult result; diff -Nru openjdk-21-21.0.8+9/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h openjdk-21-21.0.9+10/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h --- openjdk-21-21.0.8+9/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h 2025-10-13 07:49:24.000000000 +0000 @@ -18,10 +18,6 @@ #define bswap_16 _byteswap_ushort #define bswap_32 _byteswap_ulong #define bswap_64 _byteswap_uint64 -#elif defined(AIX) -#include -#define __BIG_ENDIAN BIG_ENDIAN -#define __BYTE_ORDER BIG_ENDIAN #else #include #include diff -Nru openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java --- openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -30,6 +30,7 @@ import java.awt.Rectangle; import javax.swing.ButtonModel; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.plaf.ComponentUI; @@ -71,6 +72,26 @@ } super.paintBackground(g, menuItem, bgColor); } + + /** + * Paint MenuItem. + */ + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + if (WindowsMenuItemUI.isVistaPainting()) { + WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, + arrowIcon, background, foreground, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, + menuItem, getPropertyPrefix()); + return; + } + super.paintMenuItem(g, c, checkIcon, arrowIcon, background, + foreground, defaultTextIconGap); + } + /** * Method which renders the text of the current menu item. * diff -Nru openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java --- openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -857,6 +857,7 @@ } assert menuItem == null || c == menuItem; Icon icon = getIcon(); + if (type == JCheckBoxMenuItem.class || type == JRadioButtonMenuItem.class) { AbstractButton b = (AbstractButton) c; @@ -880,19 +881,18 @@ } XPStyle xp = XPStyle.getXP(); if (xp != null) { - Skin skin; - skin = xp.getSkin(c, backgroundPart); - skin.paintSkin(g, x, y, - getIconWidth(), getIconHeight(), backgroundState); - if (icon == null) { - skin = xp.getSkin(c, part); + Skin skin = xp.getSkin(c, part); + if (icon == null || icon.getIconHeight() <= 16) { skin.paintSkin(g, x + OFFSET, y + OFFSET, state); + } else { + skin.paintSkin(g, x + OFFSET, y + icon.getIconHeight() / 2, state); } } } } if (icon != null) { - icon.paintIcon(c, g, x + OFFSET, y + OFFSET); + icon.paintIcon(c, g, x + VistaMenuItemCheckIconFactory.getIconWidth(), + y + OFFSET); } } private static WindowsMenuItemUIAccessor getAccessor( diff -Nru openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java --- openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -26,13 +26,20 @@ package com.sun.java.swing.plaf.windows; import java.awt.Color; +import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Insets; import java.awt.Rectangle; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Enumeration; +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; import javax.swing.ButtonModel; +import javax.swing.DefaultButtonModel; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; @@ -41,6 +48,7 @@ import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicMenuItemUI; +import com.sun.java.swing.SwingUtilities3; import com.sun.java.swing.plaf.windows.TMSchema.Part; import com.sun.java.swing.plaf.windows.TMSchema.State; import com.sun.java.swing.plaf.windows.XPStyle.Skin; @@ -120,6 +128,27 @@ menuItem.addPropertyChangeListener(changeListener); } + protected void installDefaults() { + super.installDefaults(); + String prefix = getPropertyPrefix(); + + if (acceleratorSelectionForeground == null || + acceleratorSelectionForeground instanceof UIResource) { + acceleratorSelectionForeground = + UIManager.getColor(prefix + ".acceleratorSelectionForeground"); + } + if (acceleratorForeground == null || + acceleratorForeground instanceof UIResource) { + acceleratorForeground = + UIManager.getColor(prefix + ".acceleratorForeground"); + } + if (disabledForeground == null || + disabledForeground instanceof UIResource) { + disabledForeground = + UIManager.getColor(prefix + ".disabledForeground"); + } + } + /** * {@inheritDoc} */ @@ -132,6 +161,90 @@ changeListener = null; } + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + if (WindowsMenuItemUI.isVistaPainting()) { + WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, + arrowIcon, background, foreground, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, + getPropertyPrefix()); + return; + } + super.paintMenuItem(g, c, checkIcon, arrowIcon, background, + foreground, defaultTextIconGap); + } + + static void paintMenuItem(WindowsMenuItemUIAccessor accessor, Graphics g, + JComponent c, Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + Color disabledForeground, + Color acceleratorSelectionForeground, + Color acceleratorForeground, + int defaultTextIconGap, JMenuItem menuItem, String prefix) { + // Save original graphics font and color + Font holdf = g.getFont(); + Color holdc = g.getColor(); + + JMenuItem mi = (JMenuItem) c; + g.setFont(mi.getFont()); + + Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight()); + SwingUtilities3.applyInsets(viewRect, mi.getInsets()); + + String acceleratorDelimiter = + UIManager.getString("MenuItem.acceleratorDelimiter"); + if (acceleratorDelimiter == null) { acceleratorDelimiter = "+"; } + Font acceleratorFont = UIManager.getFont("MenuItem.acceleratorFont"); + if (acceleratorFont == null) { + acceleratorFont = UIManager.getFont("MenuItem.font"); + } + + MenuItemLayoutHelper lh = new MenuItemLayoutHelper(mi, checkIcon, + arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter, + mi.getComponentOrientation().isLeftToRight(), mi.getFont(), + acceleratorFont, MenuItemLayoutHelper.useCheckAndArrow(menuItem), + prefix); + MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem(); + + paintBackground(accessor, g, mi, background); + SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground); + SwingUtilities3.paintIcon(g, lh, lr, holdc); + + if (lh.getCheckIcon() != null && lh.useCheckAndArrow()) { + Rectangle rect = lr.getTextRect(); + + rect.x += lh.getAfterCheckIconGap(); + + lr.setTextRect(rect); + } + if (!lh.getText().isEmpty()) { + if (lh.getHtmlView() != null) { + // Text is HTML + lh.getHtmlView().paint(g, lr.getTextRect()); + } else { + // Text isn't HTML + paintText(accessor, g, lh.getMenuItem(), + lr.getTextRect(), lh.getText()); + } + } + if (lh.getCheckIcon() != null && lh.useCheckAndArrow()) { + Rectangle rect = lr.getAccRect(); + rect.x += lh.getAfterCheckIconGap(); + lr.setAccRect(rect); + } + SwingUtilities3.paintAccText(g, lh, lr, disabledForeground, + acceleratorSelectionForeground, + acceleratorForeground); + SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); + + // Restore original graphics font and color + g.setColor(holdc); + g.setFont(holdf); + } + /** * Method which renders the text of the current menu item. * diff -Nru openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java --- openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -128,6 +128,26 @@ } /** + * Paint MenuItem. + */ + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + if (WindowsMenuItemUI.isVistaPainting()) { + WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, arrowIcon, + background, foreground, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, + getPropertyPrefix()); + return; + } + super.paintMenuItem(g, c, checkIcon, arrowIcon, background, + foreground, defaultTextIconGap); + } + + + /** * Draws the background of the menu. * @since 1.4 */ diff -Nru openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java --- openjdk-21-21.0.8+9/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -30,6 +30,7 @@ import java.awt.Rectangle; import javax.swing.ButtonModel; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.plaf.ComponentUI; @@ -73,6 +74,25 @@ } /** + * Paint MenuItem. + */ + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + if (WindowsMenuItemUI.isVistaPainting()) { + WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, + arrowIcon, background, foreground, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, + menuItem, getPropertyPrefix()); + return; + } + super.paintMenuItem(g, c, checkIcon, arrowIcon, background, + foreground, defaultTextIconGap); + } + + /** * Method which renders the text of the current menu item. * * @param g Graphics context diff -Nru openjdk-21-21.0.8+9/src/java.desktop/windows/classes/sun/awt/windows/WClipboard.java openjdk-21-21.0.9+10/src/java.desktop/windows/classes/sun/awt/windows/WClipboard.java --- openjdk-21-21.0.8+9/src/java.desktop/windows/classes/sun/awt/windows/WClipboard.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/windows/classes/sun/awt/windows/WClipboard.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -29,7 +29,9 @@ import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; +import java.lang.System.Logger.Level; import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; import sun.awt.datatransfer.DataTransferer; import sun.awt.datatransfer.SunClipboard; @@ -51,8 +53,12 @@ private boolean isClipboardViewerRegistered; + private final ReentrantLock clipboardLocked = new ReentrantLock(); + WClipboard() { super("System"); + // Register java side of the clipboard with the native side + registerClipboard(); } @Override @@ -104,18 +110,42 @@ /** * Call the Win32 OpenClipboard function. If newOwner is non-null, - * we also call EmptyClipboard and take ownership. + * we also call EmptyClipboard and take ownership. If this method call + * succeeds, it must be followed by a call to {@link #closeClipboard()}. * * @throws IllegalStateException if the clipboard has not been opened */ @Override - public native void openClipboard(SunClipboard newOwner) throws IllegalStateException; + public void openClipboard(SunClipboard newOwner) throws IllegalStateException { + if (!clipboardLocked.tryLock()) { + throw new IllegalStateException("Failed to acquire clipboard lock"); + } + try { + openClipboard0(newOwner); + } catch (IllegalStateException ex) { + clipboardLocked.unlock(); + throw ex; + } + } + /** * Call the Win32 CloseClipboard function if we have clipboard ownership, * does nothing if we have not ownership. */ @Override - public native void closeClipboard(); + public void closeClipboard() { + if (clipboardLocked.isLocked()) { + try { + closeClipboard0(); + } finally { + clipboardLocked.unlock(); + } + } + } + + private native void openClipboard0(SunClipboard newOwner) throws IllegalStateException; + private native void closeClipboard0(); + /** * Call the Win32 SetClipboardData function. */ @@ -157,16 +187,12 @@ return; } - long[] formats = null; try { - openClipboard(null); - formats = getClipboardFormats(); - } catch (IllegalStateException exc) { - // do nothing to handle the exception, call checkChange(null) - } finally { - closeClipboard(); + long[] formats = getClipboardFormats(); + checkChange(formats); + } catch (Throwable ex) { + System.getLogger(WClipboard.class.getName()).log(Level.DEBUG, "Failed to process handleContentsChanged", ex); } - checkChange(formats); } /** @@ -214,4 +240,6 @@ } }; } + + private native void registerClipboard(); } diff -Nru openjdk-21-21.0.8+9/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp openjdk-21-21.0.9+10/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp --- openjdk-21-21.0.8+9/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, 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 @@ -69,9 +69,8 @@ return; } - if (theCurrentClipboard == NULL) { - theCurrentClipboard = env->NewGlobalRef(jclipboard); - } + DASSERT(AwtClipboard::theCurrentClipboard != NULL); + DASSERT(env->IsSameObject(AwtClipboard::theCurrentClipboard, jclipboard)); jclass cls = env->GetObjectClass(jclipboard); AwtClipboard::handleContentsChangedMID = @@ -128,11 +127,13 @@ * Signature: (Lsun/awt/windows/WClipboard;)V */ JNIEXPORT void JNICALL -Java_sun_awt_windows_WClipboard_openClipboard(JNIEnv *env, jobject self, +Java_sun_awt_windows_WClipboard_openClipboard0(JNIEnv *env, jobject self, jobject newOwner) { TRY; + DASSERT(AwtClipboard::theCurrentClipboard != NULL); + DASSERT(newOwner == NULL || env->IsSameObject(AwtClipboard::theCurrentClipboard, newOwner)); DASSERT(::GetOpenClipboardWindow() != AwtToolkit::GetInstance().GetHWnd()); if (!::OpenClipboard(AwtToolkit::GetInstance().GetHWnd())) { @@ -142,10 +143,6 @@ } if (newOwner != NULL) { AwtClipboard::GetOwnership(); - if (AwtClipboard::theCurrentClipboard != NULL) { - env->DeleteGlobalRef(AwtClipboard::theCurrentClipboard); - } - AwtClipboard::theCurrentClipboard = env->NewGlobalRef(newOwner); } CATCH_BAD_ALLOC; @@ -157,7 +154,7 @@ * Signature: ()V */ JNIEXPORT void JNICALL -Java_sun_awt_windows_WClipboard_closeClipboard(JNIEnv *env, jobject self) +Java_sun_awt_windows_WClipboard_closeClipboard0(JNIEnv *env, jobject self) { TRY; @@ -297,23 +294,25 @@ { TRY; - DASSERT(::GetOpenClipboardWindow() == AwtToolkit::GetInstance().GetHWnd()); + unsigned int cFormats = 128; // Allocate enough space to hold all + unsigned int pcFormatsOut = 0; + unsigned int lpuiFormats[128] = { 0 }; - jsize nFormats = ::CountClipboardFormats(); - jlongArray formats = env->NewLongArray(nFormats); + VERIFY(::GetUpdatedClipboardFormats(lpuiFormats, 128, &pcFormatsOut)); + + jlongArray formats = env->NewLongArray(pcFormatsOut); if (formats == NULL) { throw std::bad_alloc(); } - if (nFormats == 0) { + if (pcFormatsOut == 0) { return formats; } jboolean isCopy; jlong *lFormats = env->GetLongArrayElements(formats, &isCopy), *saveFormats = lFormats; - UINT num = 0; - for (jsize i = 0; i < nFormats; i++, lFormats++) { - *lFormats = num = ::EnumClipboardFormats(num); + for (unsigned int i = 0; i < pcFormatsOut; i++, lFormats++) { + *lFormats = lpuiFormats[i]; } env->ReleaseLongArrayElements(formats, saveFormats, 0); @@ -478,4 +477,16 @@ CATCH_BAD_ALLOC_RET(NULL); } +/* + * Class: sun_awt_windows_WClipboard + * Method: registerClipboard + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_sun_awt_windows_WClipboard_registerClipboard(JNIEnv *env, jobject self) +{ + DASSERT(AwtClipboard::theCurrentClipboard == NULL); + AwtClipboard::theCurrentClipboard = env->NewGlobalRef(self); +} + } /* extern "C" */ diff -Nru openjdk-21-21.0.8+9/src/java.management/share/classes/javax/management/remote/package.html openjdk-21-21.0.9+10/src/java.management/share/classes/javax/management/remote/package.html --- openjdk-21-21.0.8+9/src/java.management/share/classes/javax/management/remote/package.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/src/java.management/share/classes/javax/management/remote/package.html 2025-10-13 07:49:24.000000000 +0000 @@ -2,7 +2,7 @@ JMX Remote API. - - - - - UpdatingBootTime - - - -

UpdatingBootTime
Bug ID:

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Component/UpdatingBootTime/UpdatingBootTime.java openjdk-21-21.0.9+10/test/jdk/java/awt/Component/UpdatingBootTime/UpdatingBootTime.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Component/UpdatingBootTime/UpdatingBootTime.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Component/UpdatingBootTime/UpdatingBootTime.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2007, 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 6461933 7194219 - @summary adjust system boot time in nowMillisUTC() frequently - @author Andrei Dmitriev : area=awt.component - @run applet/manual=yesno UpdatingBootTime.html - */ - -/* - * verifies that time updated by the system is picked up by the Java App. - */ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; -import java.util.Date; - -public class UpdatingBootTime extends Applet -{ - //Declare things used in the test, like buttons and labels here - - public void init() - { - this.setLayout (new BorderLayout ()); - - String[] instructions = - { - "1) Press the mouse over the button.", - "2) A two timestamps would be printed.", - "3) Verify that they are not differ a lot: it is okay to observe a 1 or 2 seconds difference.", - "4) Change the system time significantly(by a month or a year) by using the OS abilities.", - "5) Click on the button once again.", - "6) Printed times should still be the same. Pay attention to the Month/Year if they were changed.", - "7) It is okay to observe a 1 or 2 seconds difference and this is not a fail.", - "8) If the difference is more then 1-2 seconds noticed then the test fail; otherwise pass." - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - public void start () - { - Button b = new Button("Press me"); - b.addMouseListener(new MouseAdapter(){ - public void mousePressed(MouseEvent e){ - Sysout.println("Event occured : "+e); - Sysout.println("The event time is : "+ (new Date(e.getWhen()))); - Sysout.println("The system time is : "+ (new Date())); - } - }); - add(b); - setSize (200,200); - setVisible(true); - validate(); - }// start() -}// class UpdatingBootTime - -/* Place other classes related to the test after this line */ - - - - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Component/UpdatingBootTime.java openjdk-21-21.0.9+10/test/jdk/java/awt/Component/UpdatingBootTime.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Component/UpdatingBootTime.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Component/UpdatingBootTime.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2007, 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 6461933 7194219 + * @summary adjust system boot time in nowMillisUTC() frequently + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual UpdatingBootTime + */ + +/* + * Test verifies that time updated by the system is correctly + * picked up by the Java application. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.Date; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +public class UpdatingBootTime { + private static JFrame initialize () { + JFrame frame = new JFrame("Updating Boot Time Test Frame"); + frame.setLayout(new BorderLayout()); + JTextArea textOutput = new JTextArea("Events on the button:", 14, 40); + textOutput.setLineWrap(true); + JScrollPane textScrollPane = new JScrollPane(textOutput); + frame.add(textScrollPane, BorderLayout.CENTER); + Button b = new Button("Press me"); + frame.add(b, BorderLayout.NORTH); + b.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + textOutput.append("\nEvent occurred : " + e); + textOutput.append("\nThe event time is : " + (new Date(e.getWhen()))); + textOutput.append("\nThe system time is : " + (new Date())); + textOutput.append("\n------------------------------------"); + textOutput.setCaretPosition(textOutput.getText().length()); + } + }); + frame.pack(); + return frame; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + String instructions = + """ + 1) In the test window press "Press me" button. + 2) Two timestamps should be printed. + 3) Verify that they are not differ a lot: + it is okay to observe a 1 or 2 seconds difference. + 4) Change the system time significantly (by a month or a year) + by using the OS abilities. + 5) Click on the button once again. + 6) Printed times should still be the same. + Pay attention to the Month/Year if they were changed. + 7) It is okay to observe a 1 or 2 seconds difference and this is not a fail. + 8) If the difference is more then 1-2 seconds noticed press fail, + otherwise press pass. + """; + + PassFailJFrame.builder() + .title("Updating Boot Time Test Instructions") + .instructions(instructions) + .rows((int) instructions.lines().count() + 1) + .columns(40) + .testUI(UpdatingBootTime::initialize) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ - - - - - CursorOverlappedPanelsTest, bug ID 8007155 - - - -

See the dialog box (usually in upper left corner) for instructions

- - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest/CursorOverlappedPanelsTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2013, 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.*; -//import java.applet.Applet; -import javax.swing.BorderFactory; -import javax.swing.JApplet; -import javax.swing.JFrame; -import javax.swing.JLayeredPane; -import javax.swing.JPanel; - -/** - * @test - * @bug 8007155 - * @summary [macosx] Disabled panel takes mouse input in JLayeredPane - * @author Alexander Scherbatiy: area=java.awt.Cursor - * @run applet/manual=yesno CursorOverlappedPanelsTest.html - */ -public class CursorOverlappedPanelsTest extends JApplet { - //Declare things used in the test, like buttons and labels here - - public void init() { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout(new BorderLayout()); - - String[] instructions = { - "Verify that the Crosshair cursor from enabled panel" - + " is displayed on the panels intersection", - "1) Move the mosue cursor on the Enabled and Disabled panels" - + " intersection", - "2) Check that the Crosshair cursor is displayed ", - "If so, press PASS, else press FAIL." - }; - Sysout.createDialogWithInstructions(instructions); - - }//End init() - - public void start() { - //Get things going. Request focus, set size, et cetera - setSize(200, 200); - setVisible(true); - validate(); - try { - EventQueue.invokeAndWait(new Runnable() { - public void run() { - createAndShowGUI(); - } - }); - } catch (Exception e) { - throw new RuntimeException(e); - } - }// start() - - //The rest of this class is the actions which perform the test... - //Use Sysout.println to communicate with the user NOT System.out!! - //Sysout.println ("Something Happened!"); - private static JPanel createPanel(Point location, boolean enabled) { - final JPanel panel = new JPanel(); - panel.setOpaque(false); - panel.setEnabled(enabled); - panel.setSize(new Dimension(200, 200)); - panel.setLocation(location); - panel.setBorder(BorderFactory.createTitledBorder( - enabled ? "Enabled" : "Disabled")); - panel.setCursor(Cursor.getPredefinedCursor( - enabled ? Cursor.CROSSHAIR_CURSOR : Cursor.DEFAULT_CURSOR)); - System.out.println("cursor: " + Cursor.getPredefinedCursor(enabled ? Cursor.CROSSHAIR_CURSOR : Cursor.DEFAULT_CURSOR)); - return panel; - } - - private static void createAndShowGUI() { - final JFrame frame = new JFrame("Test"); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - JLayeredPane layeredPane = new JLayeredPane(); - layeredPane.setPreferredSize(new Dimension(400, 400)); - JPanel enabledPanel = createPanel(new Point(10, 10), true); - JPanel disabledPanel = createPanel(new Point(100, 100), false); - layeredPane.add(disabledPanel, JLayeredPane.PALETTE_LAYER); - layeredPane.add(enabledPanel, JLayeredPane.DEFAULT_LAYER); - - frame.getContentPane().add(layeredPane); - frame.pack(); - frame.setVisible(true); - } -}// class BlockedWindowTest - -/* Place other classes related to the test after this line */ -/** - * ************************************************** - * Standard Test Machinery DO NOT modify anything below -- it's a standard chunk - * of code whose purpose is to make user interaction uniform, and thereby make - * it simpler to read and understand someone else's test. - * ************************************************** - */ -/** - * This is part of the standard test machinery. It creates a dialog (with the - * instructions), and is the interface for sending text messages to the user. To - * print the instructions, send an array of strings to Sysout.createDialog - * WithInstructions method. Put one line of instructions per array entry. To - * display a message for the tester to see, simply call Sysout.println with the - * string to be displayed. This mimics System.out.println but works within the - * test harness as well as standalone. - */ -class Sysout { - - private static TestDialog dialog; - - public static void createDialogWithInstructions(String[] instructions) { - dialog = new TestDialog(new Frame(), "Instructions"); - dialog.printInstructions(instructions); - dialog.setVisible(true); - println("Any messages for the tester will display here."); - } - - public static void createDialog() { - dialog = new TestDialog(new Frame(), "Instructions"); - String[] defInstr = {"Instructions will appear here. ", ""}; - dialog.printInstructions(defInstr); - dialog.setVisible(true); - println("Any messages for the tester will display here."); - } - - public static void printInstructions(String[] instructions) { - dialog.printInstructions(instructions); - } - - public static void println(String messageIn) { - dialog.displayMessage(messageIn); - } -}// Sysout class - -/** - * This is part of the standard test machinery. It provides a place for the test - * instructions to be displayed, and a place for interactive messages to the - * user to be displayed. To have the test instructions displayed, see Sysout. To - * have a message to the user be displayed, see Sysout. Do not call anything in - * this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog(Frame frame, String name) { - super(frame, name); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); - add("North", instructionsText); - - messageText = new TextArea("", 5, maxStringLength, scrollBoth); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions(String[] instructions) { - //Clear out any current instructions - instructionsText.setText(""); - - //Go down array of instruction strings - - String printStr, remainingStr; - for (int i = 0; i < instructions.length; i++) { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i]; - while (remainingStr.length() > 0) { - //if longer than max then chop off first max chars to print - if (remainingStr.length() >= maxStringLength) { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf(' ', maxStringLength - 1); - - if (posOfSpace <= 0) { - posOfSpace = maxStringLength - 1; - } - - printStr = remainingStr.substring(0, posOfSpace + 1); - remainingStr = remainingStr.substring(posOfSpace + 1); - } //else just print - else { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append(printStr + "\n"); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage(String messageIn) { - messageText.append(messageIn + "\n"); - System.out.println(messageIn); - } -}// TestDialog class diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Cursor/CursorOverlappedPanelsTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013, 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.Cursor; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Point; +import java.lang.reflect.InvocationTargetException; +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JPanel; + +/* + * @test + * @bug 8007155 + * @summary [macosx] Disabled panel takes mouse input in JLayeredPane + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CursorOverlappedPanelsTest + */ + +public class CursorOverlappedPanelsTest extends Frame { + public static JFrame initialize() { + final JFrame frame = new JFrame("Overlapping Panels Cursor Test"); + + JLayeredPane layeredPane = new JLayeredPane(); + layeredPane.setPreferredSize(new Dimension(400, 400)); + JPanel enabledPanel = createPanel(new Point(10, 10), true); + JPanel disabledPanel = createPanel(new Point(100, 100), false); + layeredPane.add(disabledPanel, JLayeredPane.PALETTE_LAYER); + layeredPane.add(enabledPanel, JLayeredPane.DEFAULT_LAYER); + + frame.getContentPane().add(layeredPane); + frame.pack(); + return frame; + } + + private static JPanel createPanel(Point location, boolean enabled) { + final JPanel panel = new JPanel(); + panel.setOpaque(false); + panel.setEnabled(enabled); + panel.setSize(new Dimension(200, 200)); + panel.setLocation(location); + panel.setBorder(BorderFactory.createTitledBorder( + enabled ? "Enabled" : "Disabled")); + panel.setCursor(Cursor.getPredefinedCursor( + enabled ? Cursor.CROSSHAIR_CURSOR : Cursor.DEFAULT_CURSOR)); + return panel; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + String instructions = """ + 1) Move the mouse cursor into the area + of Enabled and Disabled panels intersection; + 2) Check that the crosshair cursor is displayed. + If so, press PASS, otherwise press FAIL. + """; + + PassFailJFrame.builder() + .title("Overlapping Panels Cursor Test Instructions") + .instructions(instructions) + .rows((int) instructions.lines().count() + 1) + .columns(30) + .testUI(CursorOverlappedPanelsTest::initialize) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Desktop/BrowseTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/BrowseTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Desktop/BrowseTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/BrowseTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -25,8 +25,8 @@ * @test * @bug 6255196 * @summary Verifies the function of method browse(java.net.URI uri). - * @library /java/awt/regtesthelpers - * @build PassFailJFrame + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException * @run main/manual BrowseTest */ @@ -36,6 +36,8 @@ import java.net.URI; import javax.swing.JPanel; +import jtreg.SkippedException; + public class BrowseTest extends JPanel { static final String INSTRUCTIONS = """ This test could launch default file manager to open user's home @@ -47,12 +49,6 @@ """; 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(); @@ -77,6 +73,11 @@ public static void main(String[] args) throws InterruptedException, InvocationTargetException { + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported " + + "on current platform. Further testing will not be performed"); + } + PassFailJFrame.builder() .title("Browser Test") .splitUI(BrowseTest::new) diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -27,8 +27,8 @@ * @bug 6255196 * @summary Verifies the function of methods edit(java.io.File file) and * print(java.io.File file) - * @library /java/awt/regtesthelpers - * @build PassFailJFrame + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException * @run main/manual EditAndPrintTest */ @@ -40,6 +40,8 @@ import java.lang.reflect.InvocationTargetException; import javax.swing.JPanel; +import jtreg.SkippedException; + public class EditAndPrintTest extends JPanel { static final String INSTRUCTIONS = """ @@ -49,20 +51,9 @@ If you see any EXCEPTION messages in the output press FAIL. """; - public EditAndPrintTest() { - 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(); - - if (!desktop.isSupported(Action.PRINT) && !desktop.isSupported(Action.EDIT)) { - PassFailJFrame.log("Neither EDIT nor PRINT actions are supported. Nothing to test."); - PassFailJFrame.forcePass(); - } + static Desktop desktop; + public EditAndPrintTest() { /* * Part 1: print or edit a directory, which should throw an IOException. */ @@ -111,7 +102,7 @@ writer.write("This is a temp file used to test print() method of Desktop."); writer.flush(); writer.close(); - } catch (java.io.IOException ioe){ + } catch (IOException ioe){ PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); PassFailJFrame.forceFail("Failed to create temp file for testing."); } @@ -139,6 +130,16 @@ public static void main(String args[]) throws InterruptedException, InvocationTargetException { + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported " + + "on current platform. Further testing will not be performed"); + } + + desktop = Desktop.getDesktop(); + if (!desktop.isSupported(Action.PRINT) && !desktop.isSupported(Action.EDIT)) { + throw new SkippedException("Neither EDIT nor PRINT actions are supported. Nothing to test."); + } + PassFailJFrame.builder() .title("Edit and Print test") .splitUI(EditAndPrintTest::new) diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Desktop/OpenTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/OpenTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Desktop/OpenTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Desktop/OpenTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -25,8 +25,8 @@ * @test * @bug 6255196 * @summary Verifies the function of method open(java.io.File file). - * @library /java/awt/regtesthelpers - * @build PassFailJFrame + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException * @run main/manual/othervm OpenTest */ @@ -36,6 +36,8 @@ import java.lang.reflect.InvocationTargetException; import javax.swing.JPanel; +import jtreg.SkippedException; + public class OpenTest extends JPanel { static final String INSTRUCTIONS = """ @@ -48,12 +50,6 @@ """; 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(); /* @@ -85,7 +81,7 @@ testFile = File.createTempFile("JDIC-test", ".txt", new File(System.getProperty("java.io.tmpdir"))); testFile.deleteOnExit(); - } catch (java.io.IOException ioe) { + } catch (IOException ioe) { PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); PassFailJFrame.log("Failed to create test file"); } @@ -101,6 +97,11 @@ public static void main(String[] args) throws InterruptedException, InvocationTargetException { + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported " + + "on current platform. Further testing will not be performed"); + } + PassFailJFrame.builder() .title("Mail Test") .splitUI(OpenTest::new) diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.html openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ - - - - - - FileDialogForDirectories - - - -

FileDialogForDirectories
Bug ID: 7161437

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories/FileDialogForDirectories.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 jdk.test.lib.Platform; -import test.java.awt.regtesthelpers.Sysout; - -import java.applet.Applet; -import java.awt.Button; -import java.awt.FileDialog; -import java.awt.Frame; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -public class FileDialogForDirectories extends Applet implements ActionListener { - private volatile Button showBtn; - private volatile FileDialog fd; - - @Override - public void init() { - if (!Platform.isOSX()) { - Sysout.createDialogWithInstructions(new String[]{ - "Press PASS, this test is for MacOS X only."}); - return; - } - - System.setProperty("apple.awt.fileDialogForDirectories", "true"); - - setLayout(new GridLayout(1, 1)); - - fd = new FileDialog(new Frame(), "Open"); - - showBtn = new Button("Show File Dialog"); - showBtn.addActionListener(this); - add(showBtn); - String[] instructions = { - "1) Click on 'Show File Dialog' button. A file dialog will come up.", - "2) Check that files can't be selected.", - "3) Check that directories can be selected.", - "4) Repeat steps 1 - 3 a few times for different files and directories.", - "5) If it's true then the test passed, otherwise it failed."}; - Sysout.createDialogWithInstructions(instructions); - }//End init() - - @Override - public void start() { - setSize(200, 200); - show(); - }// start() - - @Override - public void actionPerformed(ActionEvent e) { - if (e.getSource() == showBtn) { - fd.setVisible(true); - String output = fd.getFile(); - if (output != null) { - Sysout.println(output + " is selected"); - } - } - } -}// class ManualYesNoTest diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForDirectories.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForDirectories.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForDirectories.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013, 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.FileDialog; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +/* + * @test + * @bug 7161437 + * @summary We should support "apple.awt.fileDialogForDirectories" property. + * @requires (os.family == "mac") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogForDirectories + */ + +public class FileDialogForDirectories { + + private static JFrame initialize() { + System.setProperty("apple.awt.fileDialogForDirectories", "true"); + + JFrame frame = new JFrame("Directory File Dialog Test Frame"); + frame.setLayout(new BorderLayout()); + JTextArea textOutput = new JTextArea(8, 30); + textOutput.setLineWrap(true); + JScrollPane textScrollPane = new JScrollPane(textOutput); + frame.add(textScrollPane, BorderLayout.CENTER); + + FileDialog fd = new FileDialog(new Frame(), "Open"); + + Button showBtn = new Button("Show File Dialog"); + showBtn.addActionListener(e -> { + fd.setVisible(true); + String output = fd.getFile(); + if (output != null) { + textOutput.append(output + " is selected\n"); + textOutput.setCaretPosition(textOutput.getText().length()); + } + }); + frame.add(showBtn, BorderLayout.NORTH); + frame.pack(); + return frame; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + String instructions = """ + 1) Click on 'Show File Dialog' button. A file dialog will come up. + 2) Check that files can't be selected. + 3) Check that directories can be selected. + 4) Repeat steps 1 - 3 a few times for different files and directories. + 5) If it's true then the press Pass, otherwise press Fail. + """; + + PassFailJFrame.builder() + .title("Directory File Dialog Test Instructions") + .instructions(instructions) + .rows((int) instructions.lines().count() + 1) + .columns(40) + .testUI(FileDialogForDirectories::initialize) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.html openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ - - - - - - FileDialogForPackages - - - -

FileDialogForPackages
Bug ID: 8026869

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages/FileDialogForPackages.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 jdk.test.lib.Platform; -import test.java.awt.regtesthelpers.Sysout; - -import java.applet.Applet; -import java.awt.Button; -import java.awt.FileDialog; -import java.awt.Frame; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -public class FileDialogForPackages extends Applet implements ActionListener { - private static final String APPLICATIONS_FOLDER = "/Applications"; - - private volatile Button showBtn; - private volatile FileDialog fd; - - @Override - public void init() { - if (!Platform.isOSX()) { - Sysout.createDialogWithInstructions(new String[]{ - "Press PASS, this test is for MacOS X only."}); - return; - } - - System.setProperty("apple.awt.use-file-dialog-packages", "true"); - - setLayout(new GridLayout(1, 1)); - - fd = new FileDialog(new Frame(), "Open"); - fd.setDirectory(APPLICATIONS_FOLDER); - - showBtn = new Button("Show File Dialog"); - showBtn.addActionListener(this); - add(showBtn); - String[] instructions = { - "1) Click on 'Show File Dialog' button. A file dialog will come up.", - "2) Navigate to the Applications folder if not already there", - "3) Check that the application bundles can be selected and can not be navigated", - "4) If it's true then the test passed, otherwise it failed."}; - Sysout.createDialogWithInstructions(instructions); - } - - @Override - public void start() { - setSize(200, 200); - show(); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (e.getSource() == showBtn) { - fd.setVisible(true); - String output = fd.getFile(); - if (output != null) { - Sysout.println(output + " is selected"); - } - } - } -} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForPackages.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogForPackages.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogForPackages.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013, 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.FileDialog; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JButton; + +/* + * @test + * @bug 8026869 + * @summary Support apple.awt.use-file-dialog-packages property. + * @requires (os.family == "mac") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileDialogForPackages +*/ + +public class FileDialogForPackages { + + private static JButton initialize() { + System.setProperty("apple.awt.use-file-dialog-packages", "true"); + + FileDialog fd = new FileDialog((Frame) null, "Open"); + String APPLICATIONS_FOLDER = "/Applications"; + fd.setDirectory(APPLICATIONS_FOLDER); + + JButton showBtn = new JButton("Show File Dialog"); + showBtn.addActionListener(e -> { + fd.setVisible(true); + String output = fd.getFile(); + if (output != null) { + PassFailJFrame.log(output + " is selected\n"); + } + }); + return showBtn; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + String instructions = """ + 1) Click on 'Show File Dialog' button. A file dialog will come up. + 2) Navigate to the Applications folder if not already there. + 3) Check that the application bundles can be selected + but can not be navigated. + 4) If it's true then press Pass, otherwise press Fail. + """; + + PassFailJFrame.builder() + .title("Directory File Dialog Test Instructions") + .instructions(instructions) + .rows((int) instructions.lines().count() + 1) + .columns(40) + .logArea(8) + .splitUIBottom(FileDialogForPackages::initialize) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ - - - - - -FileDialogOpenDirTest - - - -

FileDialogOpenDirTest
Bug ID: 4974135

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest/FileDialogOpenDirTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2004, 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 4974135 - @summary FileDialog should open current directory by default. - @author tav@sparc.spb.su area=awt.filedialog - @run applet/manual=yesno FileDialogOpenDirTest.html -*/ - -import java.awt.*; -import java.awt.event.*; -import java.applet.*; - -public class FileDialogOpenDirTest extends Applet { - - public static void main(String[] args) { - Applet a = new FileDialogOpenDirTest(); - a.init(); - a.start(); - } - - public void init() - { - System.setProperty("sun.awt.disableGtkFileDialogs","true"); - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout (new BorderLayout ()); - - String curdir = System.getProperty("user.dir"); - - String[] instructions1 = - { - "After test started you will see 'Test Frame' with a button inside.", - "Click the button to open FileDialog.", - "Verify that the directory opened is current directory, that is:", - curdir, - "If so press PASSED, otherwise FAILED." - }; - - String[] instructions2 = - { - "The test is not applicable for current platform. Press PASSED." - }; - - Sysout.createDialogWithInstructions(Toolkit.getDefaultToolkit().getClass().getName(). - equals("sun.awt.X11.XToolkit") ? - instructions1 : instructions2); - } - - public void start() { - Frame frame = new Frame("Test Frame"); - Button open = new Button("Open File Dialog"); - - open.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - new FileDialog(new Frame()).show(); - } - }); - - frame.setLayout(new FlowLayout()); - frame.add(open); - - int x = 0; - int y = 0; - Component dlg = null; - - if ((dlg = Sysout.getDialog()) != null) { - x = dlg.getBounds().x + dlg.getBounds().width; - y = dlg.getBounds().y; - } - frame.setBounds(x, y, 150, 70); - frame.setVisible(true); - } -} - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - - public static Component getDialog() { - return dialog; - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogOpenDirTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * 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.FileDialog; +import java.awt.Frame; +import java.awt.Toolkit; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JButton; +import jtreg.SkippedException; + +/* + * @test + * @bug 4974135 + * @summary FileDialog should open current directory by default. + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @library /test/lib + * @build PassFailJFrame + * @build jtreg.SkippedException + * @run main/manual FileDialogOpenDirTest + */ + +public class FileDialogOpenDirTest { + private static JButton initialize() { + System.setProperty("sun.awt.disableGtkFileDialogs", "true"); + + JButton open = new JButton("Open File Dialog"); + open.addActionListener(e -> { + new FileDialog((Frame) null).setVisible(true); + }); + + return open; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + String toolkit = Toolkit.getDefaultToolkit().getClass().getName(); + if (!toolkit.equals("sun.awt.X11.XToolkit")) { + throw new SkippedException("Test is not designed for toolkit " + toolkit); + } + + String curdir = System.getProperty("user.dir"); + String instructions = """ + Click the \"Open File Dialog\" button below to open FileDialog. + Verify that the directory opened is current directory, that is: + $curdir, + If so press Pass, otherwise press Fail + """.replace("$curdir", curdir); + + PassFailJFrame.builder() + .title("Directory File Dialog Test Instructions") + .instructions(instructions) + .rows((int) instructions.lines().count() + 1) + .columns(40) + .splitUIBottom(FileDialogOpenDirTest::initialize) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ - - - - - - FileDialogReturnTest - - - -

FileDialogReturnTest
Bug ID:

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest/FileDialogReturnTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2007, 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 6260676 - @summary FileDialog.setDirectory() does not work properly, XToolkit - @author Dmitry.Cherepanov area=awt.filedialog - @run applet/manual=yesno FileDialogReturnTest.html -*/ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; - -/* - * Current implementation of the FileDialog class doesn't provide - * any explicit method to get the return value after the user closes - * the dialog. The only way to detect whether the user cancels the - * dialog or the user selects any file is to use the getFile() method. - * The getFile() method should return null value if the user cancels - * the dialog or non-null value if the user selects any file. - */ -public class FileDialogReturnTest extends Applet -{ - - public static void main(String[] args) { - Applet a = new FileDialogReturnTest(); - a.init(); - a.start(); - } - - public void init() - { - this.setLayout (new BorderLayout ()); - - String[] instructions = - { - " 1. The test shows the 'FileDialogReturnTest' applet which contains two text fields and one button, ", - " 2. Input something into the 'File:' text field or just keep the field empty, ", - " 3. Input something into the 'Dir:' text field or just keep the field empty, ", - " 4. Press the 'Show' button and a file dialog will appear, ", - " 5-1. Cancel the file dialog, e.g. by selecting the 'close' menu item, ", - " If the output window shows that 'file'/'dir' values is null then the test passes, otherwise the test fails, ", - " 5-2. Select any file, e.g. by pressing the 'OK' button, ", - " If the output window shows that 'file'/'dir' values is not-null then the test passes, otherwise the test fails. " - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - final TextField fileField = new TextField("", 20); - final TextField dirField = new TextField("", 20); - final Button button = new Button("Show"); - - public void start () - { - setLayout(new FlowLayout()); - - add(new Label("File:")); - add(fileField); - add(new Label("Dir:")); - add(dirField); - add(button); - - button.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showDialog(); - } - }); - - setSize (200,200); - setVisible(true); - validate(); - } - - void showDialog() - { - FileDialog fd = new FileDialog(new Frame()); - fd.setFile(fileField.getText()); - fd.setDirectory(dirField.getText()); - fd.setVisible(true); - - Sysout.println("[file=" + fd.getFile()+"]"); - Sysout.println("[dir=" + fd.getDirectory()+"]"); - } - -} - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 100; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogReturnTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileDialogReturnTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileDialogReturnTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2007, 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.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Label; +import java.awt.TextField; +import java.awt.Toolkit; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import jtreg.SkippedException; + +/* + * @test + * @bug 6260676 + * @summary FileDialog.setDirectory() does not work properly, XToolkit + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @library /test/lib + * @build PassFailJFrame + * @build jtreg.SkippedException + * @run main/manual FileDialogReturnTest + */ + +public class FileDialogReturnTest { + + private static JFrame initialize() { + JFrame frame = new JFrame("File Dialog Return Test Frame"); + GridBagConstraints gbc = new GridBagConstraints(); + GridBagLayout grid = new GridBagLayout(); + frame.setLayout(grid); + JTextArea textOutput = new JTextArea(8, 30); + textOutput.setLineWrap(true); + JScrollPane textScrollPane = new JScrollPane(textOutput); + gbc.insets = new Insets(5, 5, 5, 5); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 1; + gbc.fill = GridBagConstraints.WEST; + frame.add(new Label("File:"), gbc); + + TextField fileField = new TextField("", 20); + gbc.gridx = 1; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + frame.add(fileField, gbc); + + gbc.gridx = 0; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.WEST; + frame.add(new Label("Dir:"), gbc); + + TextField dirField = new TextField("", 20); + gbc.gridx = 1; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + frame.add(dirField, gbc); + + Button button = new Button("Show"); + gbc.gridx = 0; + gbc.gridy = 2; + gbc.gridwidth = 2; + gbc.fill = GridBagConstraints.CENTER; + frame.add(button, gbc); + + gbc.gridx = 0; + gbc.gridy = 3; + gbc.gridwidth = 2; + frame.add(textScrollPane, gbc); + + button.addActionListener(e -> { + FileDialog fd = new FileDialog(frame); + fd.setFile(fileField.getText()); + fd.setDirectory(dirField.getText()); + fd.setVisible(true); + + textOutput.append("[file=" + fd.getFile()+"]\n"); + textOutput.append("[dir=" + fd.getDirectory()+"]\n"); + textOutput.setCaretPosition(textOutput.getText().length()); + + }); + frame.pack(); + return frame; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + String instructions = """ + 1) The test shows the 'File Dialog Return Test Frame' frame + that contains two text fields, one button and an output area. + 2) Input something into the 'File:' text field or just keep the field empty. + 3) Input something into the 'Dir:' text field or just keep the field empty. + 4) Press the 'Show' button and a file dialog will appear. + 5-1) Cancel the file dialog, e.g. by selecting the 'close' menu item. + If the output window shows that 'file'/'dir' values are null + then the test passes, otherwise the test fails. + 5-2) Select any file by double clicking on it. + If the output window shows that 'file'/'dir' values are not-null + then the test passes, otherwise the test fails. + """; + + String toolkit = Toolkit.getDefaultToolkit().getClass().getName(); + if (!toolkit.equals("sun.awt.X11.XToolkit")) { + throw new SkippedException("Test is not designed for toolkit " + toolkit); + } + + PassFailJFrame.builder() + .title("File Dialog Return Test Instructions") + .instructions(instructions) + .rows((int) instructions.lines().count() + 1) + .columns(50) + .testUI(FileDialogReturnTest::initialize) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ - - - - - - FileNameOverrideTest - - - -

FileNameOverrideTest
Bug ID: 6260659

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest/FileNameOverrideTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2011, 2013, 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 6260659 - @summary File Name set programmatically in FileDialog is overridden during navigation, XToolkit - @author Dmitry.Cherepanov@SUN.COM area=awt.filedialog - @library ../../regtesthelpers - @build Sysout - @run applet/manual=yesno FileNameOverrideTest.html -*/ - -import test.java.awt.regtesthelpers.Sysout; - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.IOException; - -public class FileNameOverrideTest extends Applet implements ActionListener { - private final static String fileName = "input"; - private final static String clickDirName = "Directory for double click"; - private final static String dirPath = "."; - private Button showBtn; - private FileDialog fd; - - public void init() { - this.setLayout(new GridLayout(1, 1)); - - fd = new FileDialog(new Frame(), "Open"); - - showBtn = new Button("Show File Dialog"); - showBtn.addActionListener(this); - add(showBtn); - - try { - File tmpFileUp = new File(dirPath + File.separator + fileName); - File tmpDir = new File(dirPath + File.separator + clickDirName); - File tmpFileIn = new File(tmpDir.getAbsolutePath() + File.separator + fileName); - tmpDir.mkdir(); - tmpFileUp.createNewFile(); - tmpFileIn.createNewFile(); - } catch (IOException ex) { - throw new RuntimeException("Cannot create test folder", ex); - } - - String[] instructions = { - "1) Click on 'Show File Dialog' button. A file dialog will come up.", - "2) Double-click on '" + clickDirName + "' and click OK.", - "3) See result of the test below" - }; - Sysout.createDialogWithInstructions(instructions); - }//End init() - - public void start() { - setSize(200, 200); - show(); - }// start() - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == showBtn) { - fd.setFile(fileName); - fd.setDirectory(dirPath); - fd.setVisible(true); - String output = fd.getFile(); - if (fileName.equals(output)) { - Sysout.println("TEST PASSED"); - } else { - Sysout.println("TEST FAILED (output file - " + output + ")"); - } - } - } -}// class ManualYesNoTest diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileNameOverrideTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/FileNameOverrideTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/FileNameOverrideTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,105 @@ +/* + * 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.FileDialog; +import java.awt.Frame; +import java.awt.Toolkit; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JButton; +import jtreg.SkippedException; + +/* + * @test + * @bug 6260659 + * @summary File Name set programmatically in FileDialog is overridden during navigation, XToolkit + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @library /test/lib + * @build PassFailJFrame + * @build jtreg.SkippedException + * @run main/manual FileNameOverrideTest + */ + +public class FileNameOverrideTest { + private final static String clickDirName = "Directory for double click"; + + private static JButton initialize() { + final String fileName = "input"; + final String dirPath = System.getProperty("user.dir");; + + JButton showBtn = new JButton("Show File Dialog"); + showBtn.addActionListener(w -> { + FileDialog fd = new FileDialog((Frame) null, "Open"); + fd.setFile(fileName); + fd.setDirectory(dirPath); + fd.setVisible(true); + String output = fd.getFile(); + fd.dispose(); + if (fileName.equals(output)) { + PassFailJFrame.forcePass(); + } else { + PassFailJFrame.forceFail("File name mismatch: " + + fileName + " vs " + output); + } + }); + + try { + File tmpFileUp = new File(dirPath + File.separator + fileName); + File tmpDir = new File(dirPath + File.separator + clickDirName); + File tmpFileIn = new File(tmpDir.getAbsolutePath() + File.separator + fileName); + tmpDir.mkdir(); + tmpFileUp.createNewFile(); + tmpFileIn.createNewFile(); + } catch (IOException ex) { + throw new RuntimeException("Cannot create test folder", ex); + } + + return showBtn; + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + String instructions = """ + 1) Click on 'Show File Dialog' button. A file dialog will come up. + 2) Double-click on '$clickDirName' and click OK or Open + to confirm selection (label on the button depends on the current window manager). + 3) Test will pass or fail automatically. + """.replace("$clickDirName", clickDirName); + + String toolkit = Toolkit.getDefaultToolkit().getClass().getName(); + if (!toolkit.equals("sun.awt.X11.XToolkit")) { + throw new SkippedException("Test is not designed for toolkit " + toolkit); + } + + PassFailJFrame.builder() + .title("File Dialog Return Test Instructions") + .instructions(instructions) + .rows((int) instructions.lines().count() + 1) + .columns(50) + .splitUIBottom(FileNameOverrideTest::initialize) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.html openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ - - - - - - MultipleMode - - - -

MultipleMode
Bug ID: 6467204

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2010, 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 6467204 - @summary Need to implement "extended" native FileDialog for JFileChooser - @author dmitry.cherepanov@sun.com area=awt.filedialog - @run applet/manual=yesno MultipleMode.html -*/ - -// Note there is no @ in front of test above. This is so that the -// harness will not mistake this file as a test file. It should -// only see the html file as a test file. (the harness runs all -// valid test files, so it would run this test twice if this file -// were valid as well as the html file.) -// Also, note the area= after Your Name in the author tag. Here, you -// should put which functional area the test falls in. See the -// AWT-core home page -> test areas and/or -> AWT team for a list of -// areas. -// There are several places where ManualYesNoTest appear. It is -// recommended that these be changed by a global search and replace, -// such as ESC-% in xemacs. - - - -/** - * MultipleMode.java - * - * summary: - */ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; -import java.io.File; - - -//Manual tests should run as applet tests if possible because they -// get their environments cleaned up, including AWT threads, any -// test created threads, and any system resources used by the test -// such as file descriptors. (This is normally not a problem as -// main tests usually run in a separate VM, however on some platforms -// such as the Mac, separate VMs are not possible and non-applet -// tests will cause problems). Also, you don't have to worry about -// synchronisation stuff in Applet tests the way you do in main -// tests... - - -public class MultipleMode extends Applet -{ - //Declare things used in the test, like buttons and labels here - - public void init() - { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout (new BorderLayout ()); - - String[] instructions = - { - " 1. Turn the 'multiple' checkbox off and press the 'open' button ", - " 2. Verify that the file dialog doesn't allow the multiple file selection ", - " 3. Select any file and close the file dialog ", - " 4. The results will be displayed, verify the results ", - " 5. Turn the 'multiple' checkbox on and press the 'open' button ", - " 6. Verify that the file dialog allows the multiple file selection ", - " 7. Select several files and close the file dialog ", - " 8. The results will be displayed, verify the results " - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - public void start () - { - final Checkbox mode = new Checkbox("multiple", true); - Button open = new Button("open"); - open.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - FileDialog d = new FileDialog((Frame)null); - d.setMultipleMode(mode.getState()); - d.setVisible(true); - - // print the results - Sysout.println("DIR:"); - Sysout.println(d.getDirectory()); - Sysout.println("FILE:"); - Sysout.println(d.getFile()); - Sysout.println("FILES:"); - File files[] = d.getFiles(); - for (File f : files) { - Sysout.println(String.valueOf(f)); - } - } - }); - - setLayout(new FlowLayout()); - add(mode); - add(open); - - //Get things going. Request focus, set size, et cetera - setSize (200,200); - setVisible(true); - validate(); - - }// start() - - //The rest of this class is the actions which perform the test... - - //Use Sysout.println to communicate with the user NOT System.out!! - //Sysout.println ("Something Happened!"); - -}// class ManualYesNoTest - -/* Place other classes related to the test after this line */ - - - - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - private static boolean numbering = false; - private static int messageNumber = 0; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - /* Enables message counting for the tester. */ - public static void enableNumbering(boolean enable){ - numbering = enable; - } - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - if (numbering) { - messageIn = "" + messageNumber + " " + messageIn; - messageNumber++; - } - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/MultipleMode.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/MultipleMode.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/MultipleMode.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010, 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.Checkbox; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.io.File; + +/* + * @test + * @bug 6467204 + * @summary Need to implement "extended" native FileDialog for JFileChooser + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultipleMode +*/ + +public class MultipleMode { + + private static final String INSTRUCTIONS = + """ + 1. Verify that the 'multiple' checkbox is off and press the 'open' button + 2. Verify that the file dialog doesn't allow the multiple file selection + 3. Select any file and close the file dialog + 4. The results will be displayed, verify the results + 5. Turn the 'multiple' checkbox on and press the 'open' button + 6. Verify that the file dialog allows the multiple file selection + 7. Select several files and close the file dialog + 8. The results will be displayed, verify the results. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame + .builder() + .title("MultipleMode test instructions") + .instructions(INSTRUCTIONS) + .rows(15) + .columns(40) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .testUI(MultipleMode::init) + .build() + .awaitAndCheck(); + } + + private static Frame init() { + Frame frame = new Frame("MultipleMode"); + TextArea sysout = new TextArea("", 20, 70); + sysout.setEditable(false); + + final Checkbox mode = new Checkbox("multiple", false); + + Button open = new Button("open"); + open.addActionListener(e -> { + FileDialog d = new FileDialog(frame); + d.setMultipleMode(mode.getState()); + d.setVisible(true); + + // print the results + sysout.append("DIR:\n"); + sysout.append(" %s\n".formatted(d.getDirectory())); + sysout.append("FILE:\n"); + sysout.append(" %s\n".formatted(d.getFile())); + sysout.append("FILES:\n"); + for (File f : d.getFiles()) { + sysout.append(" %s\n".formatted(f)); + } + }); + + Panel panel = new Panel(new FlowLayout()); + panel.add(mode); + panel.add(open); + + frame.setLayout(new BorderLayout()); + frame.add(panel, BorderLayout.NORTH); + frame.add(sysout, BorderLayout.CENTER); + + frame.pack(); + + return frame; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ - - - - - - RegexpFilterTest - - - -


Bug ID:

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2007, 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 4934185 - @summary JCK1.5-runtime-interactive: XToolkit FileDialog does not work as expected - @author Dmitry.Cherepanov area=awt.filedialog - @run applet/manual=yesno RegexpFilterTest.html -*/ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; - -/* - * Motif file dialogs let the user specify a filter that controls the files that - * are displayed in the dialog. This filter is generally specified as a regular - * expression. The test verifies that Motif-like filtering works fine using - * XAWT-toolkit also. - */ -public class RegexpFilterTest extends Applet -{ - - public static void main(String[] args) { - Applet a = new RegexpFilterTest(); - a.init(); - a.start(); - } - - public void init() - { - this.setLayout (new BorderLayout ()); - - String[] instructions = - { - " 0. The test is only for X platforms", - " 1. Press the 'Show' button and a file dialog will appear, ", - " 2. Input any string into the 'Filter' text field, ", - " This filter is generally specified as a regular expression ", - " (e.g., * matches all files, while *.c matches all files that end in .c) ", - " 3. Press 'Enter' to refresh the displayed files with the filter, ", - " 4. If the list of the files contains all actual files matched the filter, ", - " then the test passed; otherwise it failed. " - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - public void start () - { - setLayout(new FlowLayout()); - Button button = new Button("Show"); - add(button); - - button.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - FileDialog fd = new FileDialog(new Frame()); - fd.setVisible(true); - } - }); - - setSize (200,200); - setVisible(true); - validate(); - } - -} - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 100; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/RegexpFilterTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/RegexpFilterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/RegexpFilterTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007, 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.swing.JButton; +import java.awt.Frame; +import java.awt.FileDialog; + +/* + * Motif file dialogs let the user specify a filter that controls the files that + * are displayed in the dialog. This filter is generally specified as a regular + * expression. The test verifies that Motif-like filtering works fine using + * XAWT-toolkit also. + */ + +/* + * @test + * @bug 4934185 + * @summary JCK1.5-runtime-interactive: XToolkit FileDialog does not work as expected + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/othervm/manual -Dsun.awt.disableGtkFileDialogs=true RegexpFilterTest +*/ +public class RegexpFilterTest { + + private static final String INSTRUCTIONS = + """ + 0. The test is only for X platforms + 1. Press the 'Show' button and a file dialog will appear, + 2. Input any string into the 'Filter' text field, + This filter is generally specified as a regular expression + (e.g., * matches all files, while *.c matches all files that end in .c) + 3. Press 'Enter' to refresh the displayed files with the filter, + 4. If the list of the files contains all actual files matched the filter, + then the test passed; otherwise it failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame + .builder() + .title("RegexpFilterTest Instructions") + .instructions(INSTRUCTIONS) + .splitUIRight(() -> { + JButton show = new JButton("show"); + show.addActionListener(e -> + new FileDialog((Frame) null).setVisible(true)); + return show; + }) + .rows(15) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ - - - - - - SaveFileNameOverrideTest - - - -

SaveFileNameOverrideTest
Bug ID: 6260659

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2011, 2014, 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 6998877 8022531 - @summary After double-click on the folder names, FileNameOverrideTest FAILED - @author Sergey.Bylokhov@oracle.com area=awt.filedialog - @library ../../regtesthelpers - @build Sysout - @run applet/manual=yesno SaveFileNameOverrideTest.html -*/ - -import test.java.awt.regtesthelpers.Sysout; - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; - -public class SaveFileNameOverrideTest extends Applet implements ActionListener { - private final static String clickDirName = "Directory for double click"; - private final static String dirPath = "."; - private Button showBtn; - private FileDialog fd; - - public void init() { - this.setLayout(new GridLayout(1, 1)); - - fd = new FileDialog(new Frame(), "Save", FileDialog.SAVE); - - showBtn = new Button("Show File Dialog"); - showBtn.addActionListener(this); - add(showBtn); - - File tmpDir = new File(dirPath + File.separator + clickDirName); - tmpDir.mkdir(); - - String[] instructions = { - "1) Click on 'Show File Dialog' button. A file dialog will come up.", - "2) Double-click on '" + clickDirName + "' and click a confirmation", - " button, it can be 'OK', 'Save' or any other platform-dependent name.", - "3) See result of the test below" - }; - - Sysout.createDialogWithInstructions(instructions); - - }//End init() - - public void start() { - setSize(200, 200); - show(); - }// start() - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == showBtn) { - fd.setFile("input"); - fd.setDirectory(dirPath); - fd.setVisible(true); - String output = fd.getFile(); - if ("input".equals(output)) { - Sysout.println("TEST PASSED"); - } else { - Sysout.println("TEST FAILED (output file - " + output + ")"); - } - } - } -}// class ManualYesNoTest diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,91 @@ +/* + * 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 javax.swing.JButton; +import java.awt.FileDialog; +import java.awt.Frame; +import java.io.File; + +/* + * @test + * @bug 6998877 8022531 + * @summary After double-click on the folder names, FileNameOverrideTest FAILED + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SaveFileNameOverrideTest + */ + +public class SaveFileNameOverrideTest { + + private final static String clickDirName = "Directory for double click"; + private static final String INSTRUCTIONS = + """ + 1) Click on the 'Show File Dialog' button. A file dialog will appear. + 2) Double-click on '%s' + 3) Click on a confirmation button. + (It can be 'OK', 'Save' or any other name depending on the platform). + 3) The test will automatically pass or fail. + """ + .formatted(clickDirName); + private final static String dirPath = "."; + + public static void main(String[] args) throws Exception { + System.out.println(System.getProperties()); + System.out.println(new File(dirPath).getAbsolutePath()); + File tmpDir = new File(dirPath + File.separator + clickDirName); + if (!tmpDir.mkdir()) { + throw new RuntimeException("Cannot create directory."); + } + tmpDir.deleteOnExit(); + + PassFailJFrame + .builder() + .title("SaveFileNameOverrideTest Instructions") + .instructions(INSTRUCTIONS) + .splitUIRight(SaveFileNameOverrideTest::getButton) + .rows(8) + .columns(40) + .build() + .awaitAndCheck(); + } + + public static JButton getButton() { + JButton showBtn = new JButton("Show File Dialog"); + showBtn.addActionListener(e -> { + FileDialog fd = + new FileDialog((Frame) null, "Save", FileDialog.SAVE); + + fd.setFile("input"); + fd.setDirectory(new File(dirPath).getAbsolutePath()); + fd.setVisible(true); + + String output = fd.getFile(); + if ("input".equals(output)) { + PassFailJFrame.forcePass(); + } else { + PassFailJFrame.forceFail("TEST FAILED (output file - " + output + ")"); + } + }); + return showBtn; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/FontMetrics/ExtremeFontSizeTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/FontMetrics/ExtremeFontSizeTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/FontMetrics/ExtremeFontSizeTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/FontMetrics/ExtremeFontSizeTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 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 @@ -24,16 +24,19 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; /* * @test - * @bug 8328896 + * @bug 8328896 8357672 * @summary test that using very large font sizes used don't break later uses */ @@ -49,34 +52,106 @@ static double[] scales = { 1.0, 900.0}; static boolean[] fms = { false, true }; + static class Key { + int fontSize; + double scale; + boolean fm; + String str; + + + Key(int fs, double sc, boolean f, String s) { + fontSize = fs; + scale = sc; + fm = f; + str = s; + } + + public boolean equals(Object o) { + return + (o instanceof Key k) && + this.fontSize == k.fontSize && + this.scale == k.scale && + this.fm == k.fm && + this.str.equals(k.str); + } + + public int hashCode() { + return fontSize + (int)scale + (fm ? 1 : 0) + str.hashCode(); + } + } + + static class Value { + int height; + double strBounds; + Rectangle pixelBounds; + Rectangle2D visualBounds; + + Value(int h, double sb, Rectangle pb, Rectangle2D vb) { + height = h; + strBounds = sb; + pixelBounds = pb; + visualBounds = vb; + } + + public boolean equals(Object o) { + return + (o instanceof Value v) && + this.height == v.height && + this.strBounds == v.strBounds && + this.pixelBounds.equals(v.pixelBounds) && + this.visualBounds.equals(v.visualBounds); + } + + public int hashCode() { + return height + (int)strBounds + pixelBounds.hashCode() + visualBounds.hashCode(); + } + } + + static Map metricsMap = new HashMap(); + public static void main(String[] args) { + Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + for (Font f : fonts) { + font = f.deriveFont(Font.PLAIN, 12); + System.out.println("Test font : " + font); + if (font.canDisplayUpTo(testString) != -1) { + System.out.println("Skipping since cannot display test string"); + continue; + } + metricsMap = new HashMap(); + testFont(); + } + } + + static void testFont() { /* run tests validating bounds etc are non-zero * then run with extreme scales for which zero is allowed - but not required * then run the first tests again to be sure they are still reasonable. */ - runTests(); - test(5_000_000, 10_000, false, testString, false); - test(5_000_000, 10_000, true, testString, false); - test(0, 0.00000001, false, testString, false); - runTests(); + runTests(true, false); + test(5_000_000, 10_000, false, testString, false, false, false); + test(5_000_000, 10_000, true, testString, false, false, false); + test(0, 0.00000001, false, testString, false, false, false); + runTests(false, true); if (failed) { throw new RuntimeException("Test failed. Check stdout log."); } } - static void runTests() { + static void runTests(boolean add, boolean check) { for (int fontSize : fontSizes) { for (double scale : scales) { for (boolean fm : fms) { - test(fontSize, scale, fm, testString, true); + test(fontSize, scale, fm, testString, true, add, check); } } } } - static void test(int size, double scale, boolean fm, String str, boolean checkAll) { + static void test(int size, double scale, boolean fm, String str, + boolean checkAll, boolean add, boolean check) { AffineTransform at = AffineTransform.getScaleInstance(scale, scale); FontRenderContext frc = new FontRenderContext(at, false, fm); @@ -114,5 +189,22 @@ System.out.println(" *** RESULTS NOT AS EXPECTED *** "); } System.out.println(); + + Key k = null; + Value v = null; + if (add || check) { + k = new Key(size, scale, fm, str); + v = new Value(height, width, pixelBounds, visualBounds); + } + if (add) { + metricsMap.put(k, v); + } + if (check) { + Value vmap = metricsMap.get(k); + if (!v.equals(vmap)) { + failed = true; + System.out.println("Values differ"); + } + } } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/DisposeParentGC/DisposeParentGC.java openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/DisposeParentGC/DisposeParentGC.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/DisposeParentGC/DisposeParentGC.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/DisposeParentGC/DisposeParentGC.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -21,7 +21,25 @@ * questions. */ -import java.awt.*; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Label; +import java.awt.List; +import java.awt.Point; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Toolkit; +import java.awt.Frame; +import java.awt.FlowLayout; import java.awt.image.BufferedImage; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; @@ -34,7 +52,6 @@ * @summary Display a dialog with a parent, the dialog contains all awt components * added to it & each components are setted with different cursors types. * Dispose the parent & collect GC. Garbage collection should happen - * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) * @library /lib/client * @build ExtendedRobot * @run main/othervm -Xmx20m DisposeParentGC @@ -100,7 +117,7 @@ child.setLocation(20, 140 * number); Button button = new Button("Press Me") ; - TextArea textArea = new TextArea(5,5); + TextArea textArea = new TextArea(5, 5); TextField textField = new TextField(10); Choice choice = new Choice(); choice.add("One"); @@ -115,15 +132,15 @@ list.add("Four"); list.add("Five"); Checkbox checkBox = new Checkbox("Hai"); - Scrollbar scrollBar = new Scrollbar(Scrollbar.VERTICAL,0,1,0,200); + Scrollbar scrollBar = new Scrollbar(Scrollbar.VERTICAL, 0, 1, 0, 200); CheckboxGroup checkboxGroup = new CheckboxGroup(); - Checkbox radioButton = new Checkbox("Hello" ,true, checkboxGroup); + Checkbox radioButton = new Checkbox("Hello", true, checkboxGroup); Canvas canvas = new Canvas(); Label label = new Label("I am label!"); Cursor customCursor = null; child.setLayout(new FlowLayout()); - canvas.setSize(100,100); + canvas.setSize(100, 100); canvas.setBackground(Color.red); button.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); @@ -138,13 +155,17 @@ /* create a custom cursor */ Toolkit toolkit = Toolkit.getDefaultToolkit(); - Dimension d = toolkit.getBestCursorSize(32,32); + Dimension d = toolkit.getBestCursorSize(32, 32); int color = toolkit.getMaximumCursorColors(); - if(!d.equals(new Dimension(0,0)) && color != 0 ) - customCursor = toolkit.createCustomCursor(new BufferedImage( 16, 16, BufferedImage.TYPE_INT_RGB ), new Point(10, 10), "custom cursor."); - else + if (!d.equals(new Dimension(0,0)) && color != 0) { + customCursor = toolkit.createCustomCursor( + new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB), + new Point(10, 10), "custom cursor."); + } + else { System.err.println("Platform doesn't support to create a custom cursor."); + } textArea.setCursor(customCursor); child.add(label); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ - - - - - - InitialMaximizedTest - - - -

InitialMaximizedTest
Bug ID: 4464714

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/InitialMaximizedTest/InitialMaximizedTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,197 +21,82 @@ * questions. */ +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + /* - test - @bug 4464714 6365898 - @summary Frames cannot be shown initially maximized - @author Valeriy Ushakov: area=toplevel - @run applet/manual=yesno InitialMaximizedTest.html + * @test + * @bug 4464714 6365898 + * @key headful + * @summary Frames cannot be shown initially maximized */ +public class InitialMaximizedTest { -/** - * InitialMaximizedTest.java - * - * summary: - */ - -import java.applet.Applet; -import java.awt.*; - - -public class InitialMaximizedTest extends Applet -{ - Frame f; - - public void init() - { - this.setLayout (new BorderLayout ()); - - String[] instructions = - { - "This test creates a frame that is initially maximized.", - "Press PASS if frame is shown initially maximized, else press FAIL" - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - public void start () - { - //Get things going. Request focus, set size, et cetera - setSize (200,200); - setVisible(true); - validate(); - - f = new Frame("The frame SHOULD be shown MAXIMIZED"); - f.setSize(300, 300); - f.setLocation(50, 50); - f.setExtendedState(Frame.MAXIMIZED_BOTH); - f.setVisible(true); - }// start() - -}// class InitialMaximizedTest - -/* Place other classes related to the test after this line */ - - - - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } + static Frame frame; - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); + public static void main(String[] args) throws Exception { + if (!Toolkit.getDefaultToolkit() + .isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { + return; + } + + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(InitialMaximizedTest::createAndShowFrame); + robot.waitForIdle(); + robot.delay(1000); + EventQueue.invokeAndWait(InitialMaximizedTest::checkMaximized); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } } + private static void checkMaximized() { + Rectangle frameBounds = frame.getBounds(); - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + Rectangle workArea = gc.getBounds(); - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); + Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + workArea.x += screenInsets.left; + workArea.y += screenInsets.top; + workArea.width -= screenInsets.left + screenInsets.right; + workArea.height -= screenInsets.top + screenInsets.bottom; + + System.out.println("Frame bounds " + frameBounds); + System.out.println("GraphicsConfiguration bounds " + gc.getBounds()); + System.out.println("Screen insets: " + screenInsets); + System.out.println("Work area: " + workArea); + + //frame bounds can exceed screen size on Windows, see 8231043 + if (!frameBounds.contains(workArea)) { + throw new RuntimeException("Frame is not maximized"); + } } -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); + private static void createAndShowFrame() { + frame = new Frame("The frame SHOULD be shown MAXIMIZED"); + frame.setSize(300, 300); + frame.setLocation(50, 50); + frame.setExtendedState(Frame.MAXIMIZED_BOTH); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + frame.dispose(); + } + }); + frame.setVisible(true); } - -}// TestDialog class +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/MiscUndecorated/ActiveAWTWindowTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/MiscUndecorated/ActiveAWTWindowTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/MiscUndecorated/ActiveAWTWindowTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/MiscUndecorated/ActiveAWTWindowTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 @@ -25,15 +25,24 @@ * @test * @key headful * @summary To check proper WINDOW_EVENTS are triggered when Frame gains or losses the focus - * @author Jitender(jitender.singh@eng.sun.com) area=AWT - * @author yan * @library /lib/client * @build ExtendedRobot * @run main ActiveAWTWindowTest */ -import java.awt.*; -import java.awt.event.*; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; public class ActiveAWTWindowTest { @@ -47,12 +56,12 @@ private boolean passed = true; private final int delay = 150; - public static void main(String[] args) { + public static void main(String[] args) throws Exception { ActiveAWTWindowTest test = new ActiveAWTWindowTest(); try { test.doTest(); } finally { - EventQueue.invokeLater(() -> { + EventQueue.invokeAndWait(() -> { if (test.frame != null) { test.frame.dispose(); } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java 2025-10-13 07:49:24.000000000 +0000 @@ -33,6 +33,7 @@ import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; @@ -42,7 +43,7 @@ * @key headful * @bug 6988428 * @summary Tests whether shape is always set - * @run main/othervm -Dsun.java2d.uiScale=1 ShapeNotSetSometimes + * @run main/othervm/timeout=300 -Dsun.java2d.uiScale=1 ShapeNotSetSometimes */ public class ShapeNotSetSometimes { @@ -147,15 +148,20 @@ robot.waitForIdle(); robot.delay(500); + Rectangle screenBounds = window.getGraphicsConfiguration().getBounds(); + BufferedImage screenCapture = robot.createScreenCapture(screenBounds); try { - colorCheck(innerPoint.x, innerPoint.y, SHAPE_COLOR, true); + colorCheck(innerPoint.x, innerPoint.y, SHAPE_COLOR, + true, screenCapture); for (Point point : pointsOutsideToCheck) { - colorCheck(point.x, point.y, BACKGROUND_COLOR, true); + colorCheck(point.x, point.y, BACKGROUND_COLOR, + true, screenCapture); } for (Point point : shadedPointsToCheck) { - colorCheck(point.x, point.y, SHAPE_COLOR, false); + colorCheck(point.x, point.y, SHAPE_COLOR, + false, screenCapture); } } finally { EventQueue.invokeAndWait(() -> { @@ -169,15 +175,12 @@ } } - private void colorCheck(int x, int y, Color expectedColor, boolean mustBeExpectedColor) { + private void colorCheck(int x, int y, Color expectedColor, + boolean mustBeExpectedColor, BufferedImage screenCapture) { int screenX = window.getX() + x; int screenY = window.getY() + y; - robot.mouseMove(screenX, screenY); - robot.waitForIdle(); - robot.delay(50); - - Color actualColor = robot.getPixelColor(screenX, screenY); + Color actualColor = new Color(screenCapture.getRGB(screenX, screenY)); System.out.printf( "Checking %3d, %3d, %35s should %sbe %35s\n", diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ - - - - - InputMethodsTest - - - - -This test is for Linux only. For other platforms please simply push "Pass". - -Test run requires some Japanese input method to be installed. - -To test JDK-7146572 fix please perform the following steps: -1. Switch on input method and type Japanese in the above text fields. -2. Push "Disable Input Methods" button. -3. Try to type Japanese again. If it can be done then the test is failed; otherwise passed. - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/InputMethods/InputMethodsTest/InputMethodsTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -21,68 +21,75 @@ * questions. */ +import java.awt.TextArea; +import java.awt.TextField; +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JComponent; /* - @test - @bug 7146572 8024122 - @summary Check if 'enableInputMethods' works properly for TextArea and TextField on Linux platform - @author a.stepanov - @run applet/manual=yesno InputMethodsTest.html + * @test + * @bug 7146572 8024122 + * @summary Check if 'enableInputMethods' works properly for TextArea and TextField on Linux platform + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual InputMethodsTest */ +public class InputMethodsTest { -import java.applet.Applet; -import java.awt.*; -import javax.swing.*; -import java.awt.event.*; + private static final String INSTRUCTIONS = """ + Test run requires some Japanese input method to be installed. - -public class InputMethodsTest extends Applet { - - TextArea txtArea = null; - TextField txtField = null; - JButton btnIM = null; - boolean inputMethodsEnabled = true; - - public void init() { - this.setLayout(new BorderLayout()); + To test the JDK-7146572 fix, please follow these steps: + 1. Enable the input method. + 2. Type Japanese in the text area and the text field to the right. + 2. Press the "Disable Input Methods" button. + 3. Try typing Japanese again. + 4. If input methods are not disabled, then press fail; + otherwise, press pass. + """; + + static boolean inputMethodsEnabled = true; + + public static void main(String[] args) throws Exception { + PassFailJFrame + .builder() + .title("InputMethodsTest Instructions") + .instructions(INSTRUCTIONS) + .splitUIRight(InputMethodsTest::createPanel) + .testTimeOut(10) + .rows(10) + .columns(40) + .build() + .awaitAndCheck(); } - public void start() { - - setSize(350, 200); + public static JComponent createPanel() { + Box verticalBox = Box.createVerticalBox(); - JPanel panel = new JPanel(); - panel.setLayout(new GridLayout(2, 1)); + TextArea textArea = new TextArea(); + verticalBox.add(textArea); - txtArea = new TextArea(); - panel.add(txtArea); + TextField textField = new TextField(); + verticalBox.add(textField); - txtField = new TextField(); - panel.add(txtField); - - add(panel, BorderLayout.CENTER); - - btnIM = new JButton(); - setBtnText(); - - btnIM.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - inputMethodsEnabled = !inputMethodsEnabled; - setBtnText(); - txtArea.enableInputMethods(inputMethodsEnabled); - txtField.enableInputMethods(inputMethodsEnabled); - } + JButton btnIM = new JButton(); + setBtnText(btnIM); + + btnIM.addActionListener(e -> { + inputMethodsEnabled = !inputMethodsEnabled; + setBtnText(btnIM); + textArea.enableInputMethods(inputMethodsEnabled); + textField.enableInputMethods(inputMethodsEnabled); }); - add(btnIM, BorderLayout.SOUTH); - - validate(); - setVisible(true); + verticalBox.add(btnIM); + return verticalBox; } - private void setBtnText() { + private static void setBtnText(JButton btnIM) { String s = inputMethodsEnabled ? "Disable" : "Enable"; btnIM.setText(s + " Input Methods"); } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Label/ContainerValidateTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/Label/ContainerValidateTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Label/ContainerValidateTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Label/ContainerValidateTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -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. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +/* + * @test + * @key headful + * @bug 4247913 + * @summary Tests that Label repaints after call Container.validate() + * @run main ContainerValidateTest + */ + +public class ContainerValidateTest extends Frame implements MouseListener { + private static Robot robot; + private static Panel currentPanel; + private static Button currentBtn; + private static Panel updatedPanel; + private static Label updatedLabel; + private static TextField updatedTxtField; + private static Button updatedBtn; + + private static volatile Rectangle btnBounds; + + Panel pnl1 = new Panel(); + Panel pnl2 = new Panel(); + Label lbl1 = new Label("Label 1"); + Label lbl2 = new Label("Label 2"); + TextField txt1 = new TextField("field1", 20); + TextField txt2 = new TextField("field2", 20); + Button btn1 = new Button("Swap 1"); + Button btn2 = new Button("Swap 2"); + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + ContainerValidateTest containerValidate = new ContainerValidateTest(); + EventQueue.invokeAndWait(containerValidate::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + containerValidate.testUI(); + } + + private void createAndShowUI() { + this.setTitle("ContainerValidateTest Test"); + pnl1.add(lbl1); + pnl1.add(txt1); + pnl1.add(btn1); + + pnl2.add(lbl2); + pnl2.add(txt2); + pnl2.add(btn2); + + btn1.addMouseListener(this); + btn2.addMouseListener(this); + + this.add(pnl1, BorderLayout.CENTER); + pack(); + setLocationRelativeTo(null); + setVisible(true); + } + + private void testUI() throws Exception { + EventQueue.invokeAndWait(() -> btnBounds + = new Rectangle(btn1.getLocationOnScreen().x, + btn1.getLocationOnScreen().y, + btn1.getWidth(), + btn1.getHeight())); + for (int i= 1; i < 4 ; i++) { + EventQueue.invokeAndWait(() -> { + currentPanel = (Panel) this.getComponent(0); + currentBtn = (Button) currentPanel.getComponent(2); + }); + + robot.mouseMove(btnBounds.x + (int) btnBounds.getWidth() / 2, + btnBounds.y + (int) btnBounds.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + //large delay set for completion of UI validate() + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + updatedPanel = (Panel) this.getComponent(0); + updatedLabel = (Label) updatedPanel.getComponent(0); + updatedTxtField = (TextField) updatedPanel.getComponent(1); + updatedBtn = (Button) updatedPanel.getComponent(2); + }); + testPanelComponents(currentBtn.getLabel()); + } + } + + private void testPanelComponents(String btnLabel) { + if (btnLabel.equals("Swap 1")) { + if (!(updatedLabel.getText().equals(lbl2.getText()) + && updatedTxtField.getText().equals(txt2.getText()) + && updatedBtn.getLabel().equals(btn2.getLabel()))) { + throw new RuntimeException("Test Failed!! Labels not repainted" + + " after Container.validate()"); + } + } else { + if (!(updatedLabel.getText().equals(lbl1.getText()) + && updatedTxtField.getText().equals(txt1.getText()) + && updatedBtn.getLabel().equals(btn1.getLabel()))) { + throw new RuntimeException("Test Failed!! Labels not repainted" + + " after Container.validate()"); + } + } + } + + @Override + public void mousePressed(MouseEvent evt) { + if (evt.getComponent() instanceof Button btn) { + if (btn.equals(btn1)) { + remove(pnl1); + add(pnl2, BorderLayout.CENTER); + } else { + remove(pnl2); + add(pnl1, BorderLayout.CENTER); + } + invalidate(); + validate(); + } + } + + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseExited(MouseEvent e) {} + + @Override + public void mouseClicked(MouseEvent e) {} +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -22,9 +22,8 @@ */ import java.awt.BorderLayout; -import java.awt.EventQueue; -import java.awt.KeyboardFocusManager; import java.awt.Frame; +import java.awt.KeyboardFocusManager; import java.awt.List; import java.awt.Panel; import java.awt.Point; @@ -51,7 +50,7 @@ * @run main KeyEventsTest */ public class KeyEventsTest { - TestState currentState; + private volatile TestState currentState; final Object LOCK = new Object(); final int ACTION_TIMEOUT = 500; @@ -66,16 +65,14 @@ r = new Robot(); KeyEventsTest app = new KeyEventsTest(); try { - EventQueue.invokeAndWait(app::initAndShowGui); + app.initAndShowGui(); r.waitForIdle(); r.delay(500); app.doTest(); } finally { - EventQueue.invokeAndWait(() -> { - if (app.keyFrame != null) { - app.keyFrame.dispose(); - } - }); + if (app.keyFrame != null) { + app.keyFrame.dispose(); + } } } @@ -184,52 +181,51 @@ throw new RuntimeException("Test failed - list isn't focus owner."); } - EventQueue.invokeAndWait(() -> { - list.deselect(0); - list.deselect(1); - list.deselect(2); - list.deselect(3); - list.deselect(4); - list.deselect(5); - list.deselect(6); - list.deselect(7); - list.deselect(8); - - int selectIndex = 0; - int visibleIndex = 0; - - if (currentState.getScrollMoved()) { - if (currentState.getKeyID() == KeyEvent.VK_PAGE_UP || - currentState.getKeyID() == KeyEvent.VK_HOME) { - selectIndex = 8; - visibleIndex = 8; - } else if (currentState.getKeyID() == KeyEvent.VK_PAGE_DOWN || - currentState.getKeyID() == KeyEvent.VK_END) { + list.deselect(0); + list.deselect(1); + list.deselect(2); + list.deselect(3); + list.deselect(4); + list.deselect(5); + list.deselect(6); + list.deselect(7); + list.deselect(8); + + int selectIndex = 0; + int visibleIndex = 0; + + if (currentState.getScrollMoved()) { + if (currentState.getKeyID() == KeyEvent.VK_PAGE_UP || + currentState.getKeyID() == KeyEvent.VK_HOME) { + selectIndex = 8; + visibleIndex = 8; + } else if (currentState.getKeyID() == KeyEvent.VK_PAGE_DOWN || + currentState.getKeyID() == KeyEvent.VK_END) { + selectIndex = 0; + visibleIndex = 0; + } + } else { + if (currentState.getKeyID() == KeyEvent.VK_PAGE_UP || + currentState.getKeyID() == KeyEvent.VK_HOME) { + if (currentState.getSelectedMoved()) { + selectIndex = 1; + } else { selectIndex = 0; - visibleIndex = 0; } - } else { - if (currentState.getKeyID() == KeyEvent.VK_PAGE_UP || - currentState.getKeyID() == KeyEvent.VK_HOME) { - if (currentState.getSelectedMoved()) { - selectIndex = 1; - } else { - selectIndex = 0; - } - visibleIndex = 0; - } else if (currentState.getKeyID() == KeyEvent.VK_PAGE_DOWN || - currentState.getKeyID() == KeyEvent.VK_END) { - if (currentState.getSelectedMoved()) { - selectIndex = 7; - } else { - selectIndex = 8; - } - visibleIndex = 8; + visibleIndex = 0; + } else if (currentState.getKeyID() == KeyEvent.VK_PAGE_DOWN || + currentState.getKeyID() == KeyEvent.VK_END) { + if (currentState.getSelectedMoved()) { + selectIndex = 7; + } else { + selectIndex = 8; } + visibleIndex = 8; } - list.select(selectIndex); - list.makeVisible(visibleIndex); - }); + } + list.select(selectIndex); + list.makeVisible(visibleIndex); + r.delay(10); r.waitForIdle(); @@ -309,7 +305,7 @@ private final boolean scrollMoved; private final int keyID; private final boolean template; - private boolean action; + private volatile boolean action; public TestState(boolean multiple, boolean selectedMoved, boolean scrollMoved, int keyID, boolean template){ this.multiple = multiple; diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Paint/ButtonRepaint.java openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/ButtonRepaint.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Paint/ButtonRepaint.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/ButtonRepaint.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -21,28 +21,32 @@ * questions. */ - -import java.awt.*; +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; /** * @test * @key headful * @bug 7090424 - * @author Sergey Bylokhov */ public final class ButtonRepaint extends Button { public static void main(final String[] args) { for (int i = 0; i < 10; ++i) { - final Frame frame = new Frame(); - frame.setSize(300, 300); - frame.setLocationRelativeTo(null); - ButtonRepaint button = new ButtonRepaint(); - frame.add(button); - frame.setVisible(true); - sleep(); - button.test(); - frame.dispose(); + Frame frame = new Frame(); + try { + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + ButtonRepaint button = new ButtonRepaint(); + frame.add(button); + frame.setVisible(true); + sleep(); + button.test(); + } finally { + frame.dispose(); + } } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Paint/CheckboxRepaint.java openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/CheckboxRepaint.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Paint/CheckboxRepaint.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/CheckboxRepaint.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -21,27 +21,32 @@ * questions. */ -import java.awt.*; +import java.awt.Checkbox; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; /** * @test * @key headful * @bug 7090424 - * @author Sergey Bylokhov */ public final class CheckboxRepaint extends Checkbox { public static void main(final String[] args) { for (int i = 0; i < 10; ++i) { - final Frame frame = new Frame(); - frame.setSize(300, 300); - frame.setLocationRelativeTo(null); - CheckboxRepaint checkbox = new CheckboxRepaint(); - frame.add(checkbox); - frame.setVisible(true); - sleep(); - checkbox.test(); - frame.dispose(); + Frame frame = new Frame(); + try { + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + CheckboxRepaint checkbox = new CheckboxRepaint(); + frame.add(checkbox); + frame.setVisible(true); + sleep(); + checkbox.test(); + } finally { + frame.dispose(); + } } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Paint/LabelRepaint.java openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/LabelRepaint.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Paint/LabelRepaint.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/LabelRepaint.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -30,21 +30,23 @@ * @test * @key headful * @bug 7090424 - * @author Sergey Bylokhov */ public final class LabelRepaint extends Label { public static void main(final String[] args) { for (int i = 0; i < 10; ++i) { - final Frame frame = new Frame(); - frame.setSize(300, 300); - frame.setLocationRelativeTo(null); - LabelRepaint label = new LabelRepaint(); - frame.add(label); - frame.setVisible(true); - sleep(); - label.test(); - frame.dispose(); + Frame frame = new Frame(); + try { + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + LabelRepaint label = new LabelRepaint(); + frame.add(label); + frame.setVisible(true); + sleep(); + label.test(); + } finally { + frame.dispose(); + } } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/Paint/ListRepaint.java openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/ListRepaint.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/Paint/ListRepaint.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/Paint/ListRepaint.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -30,26 +30,27 @@ * @test * @key headful * @bug 7090424 - * @author Sergey Bylokhov */ public final class ListRepaint extends List { - static ListRepaint listRepaint; - static Frame frame; - - public static void main(final String[] args) throws Exception { + public static void main(final String[] args) { for (int i = 0; i < 10; ++i) { + Frame frame = new Frame(); try { - EventQueue.invokeLater(ListRepaint::createAndShowGUI); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + ListRepaint list = new ListRepaint(); + list.add("1"); + list.add("2"); + list.add("3"); + list.add("4"); + list.select(0); + frame.add(list); + frame.setVisible(true); sleep(); - EventQueue.invokeAndWait(listRepaint::test); + list.test(); } finally { - EventQueue.invokeAndWait(() -> { - if (frame != null) { - frame.dispose(); - frame = null; - } - }); + frame.dispose(); } } } @@ -61,22 +62,6 @@ } } - static void createAndShowGUI() { - frame = new Frame(); - frame.setSize(300, 300); - frame.setLocationRelativeTo(null); - - listRepaint = new ListRepaint(); - listRepaint.add("1"); - listRepaint.add("2"); - listRepaint.add("3"); - listRepaint.add("4"); - listRepaint.select(0); - - frame.add(listRepaint); - frame.setVisible(true); - } - @Override public void paint(final Graphics g) { super.paint(g); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ - - - - - - HoveringAndDraggingTest - - - -

HoveringAndDraggingTest
Bug ID: 6497109

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/TextArea/TextAreaCursorTest/HoveringAndDraggingTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -21,71 +21,122 @@ * questions. */ -/* - test - @bug 6497109 - @summary Mouse cursor icons for TextArea should be correct in case of hovering or dragging mouse over different subcomponents. - @author Konstantin Voloshin: area=awt.TextArea - @run applet/manual=yesno HoveringAndDraggingTest.html -*/ - -/** - * HoveringAndDraggingTest.java - * - * summary: Mouse cursor icons for TextArea should be correct in case - * of hovering or dragging mouse over different subcomponents. - */ - +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.Frame; -import java.awt.Panel; +import java.awt.GridBagLayout; import java.awt.GridLayout; +import java.awt.Panel; import java.awt.TextArea; -import java.awt.Dialog; +import java.util.concurrent.CountDownLatch; -public class HoveringAndDraggingTest extends java.applet.Applet { - public void start() { - String[] instructions = new String[] { - "1. Notice components in test window: main-panel, box-for-text," - +" 2 scroll-sliders, and 4 scroll-buttons.", - "2. Hover mouse over box-for-text." - +" Make sure, that mouse cursor is TextCursor (a.k.a. \"beam\").", - "3. Hover mouse over each of components (see item 1), except for box-for-text." - +" Make sure, that cursor is DefaultCursor (arrow).", - "4. Drag mouse (using any mouse button) from box-for-text to every" - +" component in item 1, and also outside application window." - +" Make sure, that cursor remains TextCursor while mouse button is pressed.", - "5. Repeat item 4 for each other component in item 1, except for box-for-text," - +" _but_ now make sure that cursor is DefaultCursor.", - "6. If cursor behaves as described in items 2-3-4-5, then test passed; otherwise it failed." - }; - Sysout.createDialogWithInstructions( instructions ); +/* + * @test + * @bug 6497109 + * @summary Mouse cursor icons for TextArea should be correct in case of + * hovering or dragging mouse over different subcomponents. + * @run main/manual HoveringAndDraggingTest + */ + +public class HoveringAndDraggingTest { + static Frame frame; + static Frame instructionsFrame; + static CountDownLatch countDownLatch; + public static CountDownLatch createCountDownLatch() { + return new CountDownLatch(1); + } + + public static void main(String[] args) throws Exception { + countDownLatch = createCountDownLatch(); + EventQueue.invokeAndWait(() -> { + initialize(); + showInstructionFrame(); + }); + countDownLatch.await(); + System.out.println("Test Pass"); + } + public static void initialize() { Panel panel = new Panel(); - panel.setLayout( new GridLayout(3,3) ); + panel.setLayout(new GridLayout(3, 3)); - for( int y=0; y<3; ++y ) { - for( int x=0; x<3; ++x ) { - if( x==1 && y==1 ) { - panel.add( new TextArea( bigString() ) ); + for (int y = 0; y < 3; ++y) { + for (int x = 0; x < 3; ++x) { + if (x == 1 && y == 1) { + panel.add(new TextArea(bigString())); } else { - panel.add( new Panel() ); + panel.add(new Panel()); } } } - Frame frame = new Frame( "TextArea cursor icon test" ); - frame.setSize( 300, 300 ); - frame.add( panel ); - frame.setVisible( true ); + frame = new Frame("TextArea cursor icon test"); + frame.setSize(300, 300); + frame.setLocation(450, 400); + frame.add(panel); + frame.setVisible(true); + } + + static void showInstructionFrame() { + String INSTRUCTIONS = """ + 1. Notice components in test window: main-panel,box-for-text, + 2 scroll-sliders, and 4 scroll-buttons. + 2. Hover mouse over box-for-text. + Make sure, that mouse cursor is TextCursor(a.k.a. \"beam\"). + 3. Hover mouse over each of components (see item 1), + except for box-for-text. + Make sure, that cursor is DefaultCursor (arrow). + 4. Drag mouse (using any mouse button) from box-for-text to every" + component in item 1, and also outside application window." + Make sure, that cursor remains TextCursor + while mouse button is pressed. + 5. Repeat item 4 for each other component in item 1, + except for box-for-text + _but_ now make sure that cursor is DefaultCursor. + 6. If cursor behaves as described in items 2-3-4-5, + then test is PASS otherwise it FAILED. + """; + TextArea textArea = new TextArea(INSTRUCTIONS, 16, 65, TextArea.SCROLLBARS_NONE); + Button passBtn = new Button("PASS"); + Button failBtn = new Button("FAIL"); + Panel btnPanel = new Panel(new GridBagLayout()); + Panel panel = new Panel(new GridBagLayout()); + instructionsFrame = new Frame("Test Instructions"); + passBtn.setMaximumSize(new Dimension(100, 30)); + failBtn.setMaximumSize(new Dimension(100, 30)); + btnPanel.add(passBtn); + btnPanel.add(failBtn); + passBtn.addActionListener(e -> disposeFrames()); + failBtn.addActionListener(e -> { + disposeFrames(); + throw new RuntimeException("Test Failed"); + }); + panel.add(textArea); + panel.add(btnPanel); + instructionsFrame.add(panel); + instructionsFrame.pack(); + instructionsFrame.setLocation(300, 100); + instructionsFrame.setVisible(true); + } + + static void disposeFrames() { + countDownLatch.countDown(); + if (frame != null) { + frame.dispose(); + } + if (instructionsFrame != null) { + instructionsFrame.dispose(); + } } static String bigString() { String s = ""; - for( int lines=0; ; ++lines ) { - for( int symbols=0; symbols<100; ++symbols ) { + for (int lines = 0; ; ++lines) { + for (int symbols = 0; symbols < 100; ++symbols) { s += "0"; } - if( lines<50 ) { + if (lines < 50) { s += "\n"; } else { break; @@ -94,141 +145,3 @@ return s; } } - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/TextField/SetEchoCharTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/TextField/SetEchoCharTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/TextField/SetEchoCharTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/TextField/SetEchoCharTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,178 @@ +/* + * 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.Button; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import jdk.test.lib.Platform; + +/* + * @test + * @bug 4124697 + * @key headful + * @summary Make sure that after setting and then changing the echo + * character again, the TextField continues to function as expected. + * @library /test/lib + * @build jdk.test.lib.Platform + * @run main SetEchoCharTest + */ + +public class SetEchoCharTest { + private static Frame frame; + private static Robot robot; + private static TextField tfPassword; + private static Button btn1; + private static Button btn2; + private static volatile Point btn1Loc; + private static volatile Point btn2Loc; + + private static final String CHANGE = "Change echo char"; + private static final String PRINT = "Print text"; + private static final String INITIAL_TEXT = "DefaultPwd"; + private static final String CHANGED_TEXT = "NewPwd"; + private static final char NEW_ECHO_CHAR = '*'; + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(50); + + EventQueue.invokeAndWait(() -> createAndShowUI()); + robot.waitForIdle(); + robot.delay(1000); + + testEchoChar(); + robot.waitForIdle(); + robot.delay(200); + + testNewEchoChar(); + robot.waitForIdle(); + robot.delay(200); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("SetEchoCharTest"); + frame.setLayout(new FlowLayout()); + + Label label = new Label("Pwd:"); + tfPassword = new TextField(INITIAL_TEXT, 10); + tfPassword.setEchoChar('X'); + tfPassword.addActionListener((ActionListener) e -> { + if (e.getActionCommand().equals(CHANGED_TEXT)) { + //check the 2nd condition only if ActionEvent + //is triggered by changed text + if (!(tfPassword.getText().equals(CHANGED_TEXT) + && tfPassword.getEchoChar() == NEW_ECHO_CHAR)) { + throw new RuntimeException("Test Failed!!! TextField not working" + + " as expected after echo char change"); + } + } + }); + frame.add(label); + frame.add(tfPassword); + + btn1 = new Button(PRINT); + btn1.addActionListener(new BtnActionListener()); + frame.add(btn1); + + btn2 = new Button(CHANGE); + btn2.addActionListener(new BtnActionListener()); + frame.add(btn2); + frame.setSize(200,200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void testEchoChar() throws Exception { + EventQueue.invokeAndWait(() -> { + btn1Loc = btn1.getLocationOnScreen(); + btn2Loc = btn2.getLocationOnScreen(); + }); + + robot.mouseMove(btn1Loc.x + btn1.getWidth() / 2, + btn1Loc.y + btn1.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + + robot.mouseMove(btn2Loc.x + btn2.getWidth() / 2, + btn2Loc.y + btn2.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + } + + private static void testNewEchoChar() { + StringSelection stringSelection = new StringSelection(CHANGED_TEXT); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(stringSelection, stringSelection); + + int ctrlKey = Platform.isOSX() ? KeyEvent.VK_META : KeyEvent.VK_CONTROL; + robot.keyPress(ctrlKey); + robot.keyPress(KeyEvent.VK_V); + robot.keyRelease(KeyEvent.VK_V); + robot.keyRelease(ctrlKey); + + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + } + + private static class BtnActionListener implements ActionListener { + public void actionPerformed(ActionEvent evt) { + String ac = evt.getActionCommand(); + if (CHANGE.equals(ac)) { + tfPassword.setText(""); + tfPassword.setEchoChar(NEW_ECHO_CHAR); + tfPassword.requestFocus(); + } + if (PRINT.equals(ac)) { + if (!tfPassword.getText().equals(INITIAL_TEXT)) { + throw new RuntimeException("Test Failed!!!" + + " Initial text not as expected"); + } + } + } + } +} + diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/TextField/SetEchoCharWordOpsTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/TextField/SetEchoCharWordOpsTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/TextField/SetEchoCharWordOpsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/TextField/SetEchoCharWordOpsTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -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. + */ + +import java.awt.FlowLayout; +import java.awt.Label; +import java.awt.TextField; +import javax.swing.JPanel; + +import jdk.test.lib.Platform; + +/* + * @test + * @bug 6191897 + * @summary Verifies that ctrl+left/right does not move word-by-word in a TextField + * with echo character set + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jdk.test.lib.Platform + * @run main/manual SetEchoCharWordOpsTest + */ + +public class SetEchoCharWordOpsTest { + + public static void main(String[] args) throws Exception { + String selectAllKey; + String moveKeys; + String selectKeys; + + if (Platform.isOSX()) { + selectAllKey = "Cmd + A"; + moveKeys = "Alt + Right/Left"; + selectKeys = "Shift + Alt + Right/Left"; + } else { + selectAllKey = "Ctrl + A"; + moveKeys = "Ctrl + Right/Left"; + selectKeys = "Shift + Ctrl + Right/Left"; + } + + String instructions = + "The password field (in the bottom panel) in this test contains" + + " a few words (3 words).\n" + + "Move the focus to the text field and press " + selectAllKey + ".\n" + + "Try moving the caret word-by-word with " + moveKeys + " or" + + " extending selection with " + selectKeys + "." + + " You should NOT be able to do that.\n\n" + + "If you are able to move the caret word-by-word press FAIL," + + " else press PASS."; + + PassFailJFrame.builder() + .title("SetEchoCharClipboard Instructions") + .instructions(instructions) + .rows((int) instructions.lines().count() + 3) + .columns(45) + .splitUIBottom(SetEchoCharWordOpsTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + + private static JPanel createAndShowUI() { + JPanel jPanel = new JPanel(); + TextField tf = new TextField("one two three", 15); + Label tfLabel = new Label("Password Field:"); + + jPanel.setLayout(new FlowLayout()); + tf.setEchoChar('*'); + jPanel.add(tfLabel); + jPanel.add(tf); + return jPanel; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.html openjdk-21-21.0.9+10/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ - - - - - - - DblClickActionEventTest - - - -

DblClickActionEventTest
Bug ID: 6284070

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2014, 2018, 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 6284070 - @summary Tests that ActionEvent is generated when a tray icon is double-clicked - @library ../../regtesthelpers - @build Sysout - @author artem.ananiev: area=awt.tray - @run applet/manual=yesno DblClickActionEventTest.html -*/ - -import java.applet.*; - -import java.awt.*; -import java.awt.event.*; -import java.awt.image.*; - -import jdk.test.lib.Platform; -import test.java.awt.regtesthelpers.Sysout; - -public class DblClickActionEventTest extends Applet { - boolean traySupported; - - public void init() { - this.setLayout(new BorderLayout()); - - String[] instructions; - traySupported = SystemTray.isSupported(); - if (traySupported) { - String clickInstruction; - if (Platform.isOSX()) { - clickInstruction = "right"; - } else { - clickInstruction = "left"; - } - instructions = new String[]{ - "When the test starts an icon is added to the SystemTray area.", - " Double-click on it with a " + clickInstruction + " button and make sure that", - " ACTION_PERFORMED event is sent to Java (all the clicks and", - " action events are shown below these instructions).", - "Then, if your system allows the tray icon to get focus (for", - " example, windows 2000 or windows XP), double-click on the", - " icon with SPACE button and single-click with RETURN button.", - " Both of them must also trigger ACTION_PERFORMED event.", - "If you see ACTION_PERFORMED events after each of your actions", - " (either mouse clicks or key presses), press PASS, else FAIL" - }; - } else { - instructions = new String[]{ - "The test cannot be run because SystemTray is not supported.", - "Simply press PASS button." - }; - } - Sysout.createDialogWithInstructions(instructions); - } - - public void start() { - setSize(200, 200); - setVisible(true); - validate(); - - if (!traySupported) { - return; - } - - 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.setColor(Color.RED); - g.fillRect(6, 6, 20, 20); - g.dispose(); - - SystemTray tray = SystemTray.getSystemTray(); - TrayIcon icon = new TrayIcon(img); - icon.setImageAutoSize(true); - icon.addActionListener(ev -> Sysout.println(ev.toString())); - icon.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent ev) { - Sysout.println(ev.toString()); - } - } - ); - - try { - tray.add(icon); - } catch (AWTException e) { - Sysout.println(e.toString()); - Sysout.println("!!! The test coudn't be performed !!!"); - } - } -} - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.html openjdk-21-21.0.9+10/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ - - - - - - ImageDecoratedDnD - - - -

ImageDecoratedDnD
Bug ID: 4874070

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.java openjdk-21-21.0.9+10/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/dnd/ImageDecoratedDnD/ImageDecoratedDnD.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -21,177 +21,87 @@ * questions. */ -/* - test %W% %E% - @bug 4874070 - @summary Tests basic DnD functionality - @author Your Name: Alexey Utkin area=dnd - @run applet/manual=yesno ImageDecoratedDnD.html -*/ - -import java.applet.Applet; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Panel; import java.awt.dnd.DragSource; +/* + * @test + * @bug 4874070 + * @summary Tests CTRL + DnD functionality + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ImageDecoratedDnD + */ +public class ImageDecoratedDnD { + private static final String INSTRUCTIONS = """ + When test runs a Frame which contains a yellow button labeled + "Drag ME!" and a RED Panel will appear. + + 1. Click on the button and drag it to the red panel while holding + the "CTRL" key on the keyboard. + + 2. When the mouse enters the red panel during the drag, the panel + should turn yellow. + + On systems that supports pictured drag, the image under the + drag-cursor should appear. + "Image under drag-cursor" is a translucent blue rectangle + red + circle and includes an anchor that is shifted from top-left + corner of the picture to inside the picture to 10pt + in both dimensions. + + On Windows, the image under the cursor would be visible ONLY over + drop targets with activated extended D'n'D support. + It means the image may not be displayed when dragging over some + windows, this is not an error. + The image should be displayed when dragging over the red/yellow panel. + + 3. Release the mouse button. + + The panel should turn red again and a yellow button labeled + "Drag ME!" should appear inside the panel. You should be able + to repeat this operation multiple times. + + If above is true 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() + 2) + .columns(38) + .testUI(ImageDecoratedDnD::createUI) + .build() + .awaitAndCheck(); + } -public class ImageDecoratedDnD extends Applet { - //Declare things used in the test, like buttons and labels here - - public void init() { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout(new BorderLayout()); - - String[] instructions = - { - "A Frame, which contains a yellow button labeled \"Drag ME!\" and ", - "a red panel, will appear below. ", - "1. Click on the button and drag to the red panel. ", - "2. When the mouse enters the red panel during the drag, the panel ", - "should turn yellow. On the systems that supports pictured drag, ", - "the image under the drag-cursor should appear (ancor is shifted ", - "from top-left corner of the picture inside the picture to 10pt in both dimensions ). ", - "In WIN32 systems the image under cursor would be visible ONLY over ", - "the drop targets with activated extended OLE D\'n\'D support (that are ", - "the desktop and IE ).", - "3. Release the mouse button.", - "The panel should turn red again and a yellow button labeled ", - "\"Drag ME!\" should appear inside the panel. You should be able ", - "to repeat this operation multiple times." - }; - Sysout.createDialogWithInstructions(instructions); - - }//End init() - - public void start() { - Frame f = new Frame("Use keyboard for DnD change"); + public static Frame createUI() { + Frame frame = new Frame("Ctrl + Drag - Image DnD test"); Panel mainPanel; Component dragSource, dropTarget; - f.setBounds(0, 400, 200, 200); - f.setLayout(new BorderLayout()); + frame.setSize(400, 400); + frame.setLayout(new BorderLayout()); mainPanel = new Panel(); mainPanel.setLayout(new BorderLayout()); - mainPanel.setBackground(Color.blue); + mainPanel.setBackground(Color.BLUE); - dropTarget = new DnDTarget(Color.red, Color.yellow); - dragSource = new DnDSource("Drag ME! (" + (DragSource.isDragImageSupported()?"with ":"without") + " image)" ); + dropTarget = new DnDTarget(Color.RED, Color.YELLOW); + dragSource = new DnDSource("Drag ME! (" + + (DragSource.isDragImageSupported() ? "with " : "without") + " image)"); mainPanel.add(dragSource, "North"); mainPanel.add(dropTarget, "Center"); - f.add(mainPanel, BorderLayout.CENTER); - - f.setVisible(true); - }// start() -}// class DnDAcceptanceTest - - -/** - * ************************************************* - * Standard Test Machinery - * DO NOT modify anything below -- it's a standard - * chunk of code whose purpose is to make user - * interaction uniform, and thereby make it simpler - * to read and understand someone else's test. - * ************************************************** - */ -class Sysout { - private static TestDialog dialog; - - public static void createDialogWithInstructions(String[] instructions) { - dialog = new TestDialog(new Frame(), "Instructions"); - dialog.printInstructions(instructions); - dialog.show(); - println("Any messages for the tester will display here."); - } - - public static void createDialog() { - dialog = new TestDialog(new Frame(), "Instructions"); - String[] defInstr = {"Instructions will appear here. ", ""}; - dialog.printInstructions(defInstr); - dialog.show(); - println("Any messages for the tester will display here."); - } - - - public static void printInstructions(String[] instructions) { - dialog.printInstructions(instructions); - } - - - public static void println(String messageIn) { - dialog.displayMessage(messageIn); + frame.add(mainPanel, BorderLayout.CENTER); + frame.setAlwaysOnTop(true); + return frame; } - -}// Sysout class - - -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog(Frame frame, String name) { - super(frame, name); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); - add("North", instructionsText); - - messageText = new TextArea("", 5, maxStringLength, scrollBoth); - add("South", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions(String[] instructions) { - //Clear out any current instructions - instructionsText.setText(""); - - //Go down array of instruction strings - - String printStr, remainingStr; - for (int i = 0; i < instructions.length; i++) { - //chop up each into pieces maxSringLength long - remainingStr = instructions[i]; - while (remainingStr.length() > 0) { - //if longer than max then chop off first max chars to print - if (remainingStr.length() >= maxStringLength) { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf(' ', maxStringLength - 1); - - if (posOfSpace <= 0) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring(0, posOfSpace + 1); - remainingStr = remainingStr.substring(posOfSpace + 1); - } - //else just print - else { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append(printStr + "\n"); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage(String messageIn) { - messageText.append(messageIn + "\n"); - } - -}// TestDialog class - +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/ClickEventsTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/ClickEventsTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/ClickEventsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/ClickEventsTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2000, 2025, 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 4087762 + @summary Sometimes click events are missing when you click the color components alternately. + @key headful + @library /test/jdk/java/awt/regtesthelpers + @build Util + @run main ClickEventsTest +*/ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Robot; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import test.java.awt.regtesthelpers.Util; + +public class ClickEventsTest { + static Frame frame; + static ColorComponent redComponent; + static ColorComponent blueComponent; + static Robot robot; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(ClickEventsTest::createAndShowGUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void test() throws Exception { + robot = new Robot(); + robot.waitForIdle(); + robot.delay(500); + + for (int i = 0; i < 10; i++) { + redComponent.clickAndCheck(); + blueComponent.clickAndCheck(); + } + } + + private static void createAndShowGUI() { + frame = new Frame("ClickEventsTest"); + redComponent = new ColorComponent(Color.RED); + blueComponent = new ColorComponent(Color.BLUE); + + frame.add("North", redComponent); + frame.add("South", blueComponent); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + static class ColorComponent extends Component { + public Color myColor; + + private final CyclicBarrier barrier = new CyclicBarrier(2); + + private final MouseAdapter mouseAdapter = new MouseAdapter() { + public void mouseClicked(MouseEvent event) { + System.out.println(myColor + " area clicked"); + try { + barrier.await(1, TimeUnit.SECONDS); + } catch (InterruptedException | BrokenBarrierException | TimeoutException e) { + throw new RuntimeException(e); + } + } + }; + + public ColorComponent(Color c) { + myColor = c; + addMouseListener(mouseAdapter); + } + + public Dimension getPreferredSize() { + return new Dimension(200, 100); + } + + public void paint(Graphics g) { + g.setColor(myColor); + g.fillRect(0, 0, 200, 100); + } + + public void clickAndCheck() throws InterruptedException, BrokenBarrierException { + barrier.reset(); + Util.clickOnComp(this, robot); + try { + barrier.await(1, TimeUnit.SECONDS); + } catch (TimeoutException e) { + throw new RuntimeException(myColor + " was not clicked"); + } + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/FrenchKeyboard.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000, 2025, 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 4308606 + * @summary Tests whether the keys on the numeric keyboard work + * correctly under French input locale. + * @key i18n + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrenchKeyboard + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; + +public class FrenchKeyboard extends Frame { + static String INSTRUCTIONS = """ + This test is intended for computers with French input method. If French + input method can not be enabled or your keyboard does not have a numeric + keypad press "Pass" to skip the test. + Make sure that French input method is active and the NumLock is on. + Click on the text field in the window called "Check your keys" + and type once of each of the following keys on the numeric keypad: + /*-+1234567890 + If all the expected characters are displayed exactly once press "Pass". + If any characters do not display or display multiple times press "Fail". + """; + + public FrenchKeyboard() { + super("Check your keys"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + add(tf, BorderLayout.CENTER); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("FrenchKeyboard Instructions") + .instructions(INSTRUCTIONS) + .testUI(FrenchKeyboard::new) + .build() + .awaitAndCheck(); + } +} + diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/HomeEndKeyTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1999, 2025, 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 4268912 4115514 + * summary Ensures that KeyEvent has right results for the following + * non-numpad keys: Home/Eng/PageUp/PageDn + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HomeEndKeyTest + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + + +public class HomeEndKeyTest extends Frame implements KeyListener { + static String INSTRUCTIONS = """ + Before starting this test make sure that system shortcuts and + keybindings for the keys in the list below are disabled. + For example pressing "Print Screen" key should not launch + screen capturing software. + Click on the text field in the window named "Check keyCode values" + and one by one start typing the keys in the list below. + (If you do not have some of the keys on your keyboard skip it + and move to the next line). + After clicking each key look at the log area - the printed name + and key code should correspond to the ones for the key you typed. + Note that on some systems the graphical symbol for the key + can be printed instead of the symbolic name. + If you do not encounter unexpected key codes for the keys you typed, + press "Pass". Otherwise press "Fail". + + Key Keycode + ------------------------- + PrintScreen 154 + ScrollLock 145 + Pause 19 + + Insert 155 + Del 127 + Home 36 + End 35 + PageUp 33 + PageDown 34 + + Left Arrow 37 + Up Arrow 38 + Right Arrow 39 + Down Arrow 40 + """; + + public HomeEndKeyTest() { + super("Check KeyCode values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + pack(); + } + + public void keyPressed(KeyEvent evt) { + printKey(evt); + } + + public void keyTyped(KeyEvent ignore) { + } + + public void keyReleased(KeyEvent evt) { + printKey(evt); + } + + protected void printKey(KeyEvent evt) { + String str; + switch (evt.getID()) { + case KeyEvent.KEY_PRESSED: + str = "KEY_PRESSED"; + break; + case KeyEvent.KEY_RELEASED: + str = "KEY_RELEASED"; + break; + default: + str = "unknown type"; + } + + str = str + ":name=" + KeyEvent.getKeyText(evt.getKeyCode()) + + " keyCode=" + evt.getKeyCode(); + PassFailJFrame.log(str); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("HomeEndKeyTest Instructions") + .instructions(INSTRUCTIONS) + .logArea(20) + .testUI(HomeEndKeyTest::new) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/KeyEvent/KeyCharTest/KeyCharTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/KeyCharTest/KeyCharTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/KeyEvent/KeyCharTest/KeyCharTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/KeyCharTest/KeyCharTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, 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 @@ -23,7 +23,7 @@ /* @test - @bug 5013984 + @bug 5013984 8360647 @summary Tests KEY_PRESSED has the same KeyChar as KEY_RELEASED @key headful @run main KeyCharTest @@ -37,7 +37,7 @@ import java.util.HashMap; public class KeyCharTest extends Frame implements KeyListener { - HashMap transMap = new HashMap(); + HashMap transMap = new HashMap<>(); public void keyTyped(KeyEvent e){ } @@ -47,22 +47,35 @@ } public void keyReleased(KeyEvent e){ - Object value = transMap.get(e.getKeyCode()); - if (value != null && e.getKeyChar() != ((Character)value).charValue()) { + Character value = transMap.get(e.getKeyCode()); + if (value != null && e.getKeyChar() != value) { throw new RuntimeException("Wrong KeyChar on KEY_RELEASED "+ KeyEvent.getKeyText(e.getKeyCode())); } } - public void start () { + private void testKeyRange(Robot robot, int start, int end) { + System.out.printf("\nTesting range on %d to %d\n", start, end); + for(int vkey = start; vkey <= end; vkey++) { + try { + robot.keyPress(vkey); + robot.keyRelease(vkey); + System.out.println(KeyEvent.getKeyText(vkey) + " " + vkey); + } catch (RuntimeException ignored) {} + } + robot.delay(100); + } + + public void start() throws Exception { + Robot robot = new Robot(); addKeyListener(this); setLocationRelativeTo(null); setSize(200, 200); setVisible(true); requestFocus(); + boolean wasNumlockPressed = false; try { - Robot robot = new Robot(); robot.setAutoDelay(10); robot.setAutoWaitForIdle(true); robot.delay(100); @@ -72,22 +85,25 @@ robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); - for(int vkey = 0x20; vkey < 0x7F; vkey++) { - try { - robot.keyPress(vkey); - robot.keyRelease(vkey); - System.out.println(KeyEvent.getKeyText(vkey) + " " + vkey); - } catch (RuntimeException e) { - } - } - robot.delay(100); + testKeyRange(robot, 0x20, 0x7E); + + // Try again with a different numpad state. + robot.keyPress(KeyEvent.VK_NUM_LOCK); + robot.keyRelease(KeyEvent.VK_NUM_LOCK); + wasNumlockPressed = true; + + testKeyRange(robot, KeyEvent.VK_NUMPAD0, KeyEvent.VK_DIVIDE); } catch(Exception e){ - e.printStackTrace(); throw new RuntimeException("Exception while performing Robot actions."); + } finally { + if (wasNumlockPressed) { + robot.keyPress(KeyEvent.VK_NUM_LOCK); + robot.keyRelease(KeyEvent.VK_NUM_LOCK); + } } } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { KeyCharTest test = new KeyCharTest(); try { test.start(); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/KeyEvent/NumpadTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/NumpadTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/KeyEvent/NumpadTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/KeyEvent/NumpadTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1998, 2025, 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 4083691 + * @summary Ensures that KeyEvent has right results for the following + * keys \*-+ + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NumpadTest + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.lang.reflect.InvocationTargetException; + + +public class NumpadTest extends Frame implements KeyListener { + static String INSTRUCTIONS = """ + This test requires a keyboard with a numeric keypad (numpad). + If your keyboard does not have a numpad press "Pass" to skip testing. + Make sure NumLock is on. + Click on the text field in the window named "Check KeyChar values". + Then, type the following keys/characters in the TextField. + using the numpad keys: + /*-+ + + Verify that the keyChar and keyCode is correct for each key pressed. + Remember that the keyCode for the KEY_TYPED event should be zero. + Also verify that the character you typed appears in the TextField. + + Key Name keyChar Keycode + ------------------------------------- + / Divide / 47 111 + * Multiply * 42 106 + - Subtract - 45 109 + + Add + 43 107 + + Now repeat with the NumLock off. + + If all keycodes are valid and expected characters appear + in the text field press "Pass". Otherwise press "Fail". + """; + + public NumpadTest() { + super("Check KeyChar values"); + setLayout(new BorderLayout()); + TextField tf = new TextField(30); + tf.addKeyListener(this); + add(tf, BorderLayout.CENTER); + pack(); + } + public void keyPressed(KeyEvent evt) { + printKey(evt); + } + + public void keyTyped(KeyEvent evt) { + printKey(evt); + } + + public void keyReleased(KeyEvent evt) { + printKey(evt); + } + + protected void printKey(KeyEvent evt) { + switch (evt.getID()) { + case KeyEvent.KEY_TYPED: + break; + case KeyEvent.KEY_PRESSED: + break; + case KeyEvent.KEY_RELEASED: + break; + default: + return; + } + + if (evt.isActionKey()) { + PassFailJFrame.log("params= " + evt.paramString() + " KeyChar: " + + (int) evt.getKeyChar() + " Action Key"); + } else { + PassFailJFrame.log("params= " + evt.paramString() + " KeyChar: " + + (int) evt.getKeyChar()); + } + } + + public static void main(String[] args) throws InterruptedException, InvocationTargetException { + PassFailJFrame.builder() + .title("NumpadTest Instructions") + .instructions(INSTRUCTIONS) + .logArea(20) + .testUI(NumpadTest::new) + .build() + .awaitAndCheck(); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.html openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ - - - - - - AWTPanelSmoothWheel - - - -

AWTPanelSmoothWheel
Bug ID: 6730447

- -

See the dialog box (usually in upper left corner) for instructions

- - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel/AWTPanelSmoothWheel.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2009, 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 6730447 - @summary Support for high resolution mouse wheel is still incomplete. AWT panel needs to be supported - @author dmitry.cherepanov@...: area=awt.mouse - @run applet/manual=yesno AWTPanelSmoothWheel.html -*/ - -/** - * AWTPanelSmoothWheel.java - * - * summary: - */ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; - -//Manual tests should run as applet tests if possible because they -// get their environments cleaned up, including AWT threads, any -// test created threads, and any system resources used by the test -// such as file descriptors. (This is normally not a problem as -// main tests usually run in a separate VM, however on some platforms -// such as the Mac, separate VMs are not possible and non-applet -// tests will cause problems). Also, you don't have to worry about -// synchronisation stuff in Applet tests the way you do in main -// tests... - - -public class AWTPanelSmoothWheel extends Applet -{ - //Declare things used in the test, like buttons and labels here - - public void init() - { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout (new BorderLayout ()); - - String[] instructions = - { - " the test is relevant for windows platforms and ", - " mouses with high-resolution wheel, please just press pass if it's not the case ", - " place the mouse cursor above the green panel and rotate the mouse wheel " , - " the test will print all mouse wheel messages into the logging panel, ", - " please make sure that some of the messages have non-zero 'wheelRotation' value ", - " in this case the test passes, otherwise it fails, ", - " please make sure the test works OK if the mouse wheel is rotated very slow " - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - public void start () - { - Panel panel = new Panel(); - panel.setBackground(Color.green); - panel.addMouseWheelListener(new MouseWheelListener() { - public void mouseWheelMoved(MouseWheelEvent e) { - Sysout.println(e.toString()); - } - }); - - //Get things going. Request focus, set size, et cetera - setSize (200,200); - setLayout(new BorderLayout()); - add(panel, BorderLayout.CENTER); - setVisible(true); - validate(); - - //What would normally go into main() will probably go here. - //Use System.out.println for diagnostic messages that you want - // to read after the test is done. - //Use Sysout.println for messages you want the tester to read. - - }// start() - - //The rest of this class is the actions which perform the test... - - //Use Sysout.println to communicate with the user NOT System.out!! - //Sysout.println ("Something Happened!"); - -}// class ManualYesNoTest - -/* Place other classes related to the test after this line */ - - - - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/AWTPanelSmoothWheel.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009, 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.MouseWheelEvent; +import javax.swing.JOptionPane; + +/* + * @test + * @bug 6730447 + * @summary To verify the support for high resolution mouse wheel. + * AWT panel needs to support high-res mouse wheel rotation. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AWTPanelSmoothWheel + */ + +public class AWTPanelSmoothWheel { + private static int wheelEventCount = 0; + private static int hiResWheelCount = 0; + private static final String WARNING_MSG = "WARNING !!!" + + " You might NOT be using a hi-res mouse."; + private static final String INSTRUCTIONS = """ + + + This test is relevant on platforms with high-resolution mouse wheel + or a trackpad can be used too. + Please press PASS if this is not the case.

+ + Place the mouse cursor above the green panel and rotate the mouse wheel, + the test will print mouse wheel event messages in the format + [Event#, WheelRotation, PreciseWheelRotation] into the logging + panel below the instruction window.

+ + A hi-res mouse/trackpad is one which produces MouseWheelEvents having: +
 Math.abs(preciseWheelRotation) < 1. 

+ + Check if the test works OK when the mouse-wheel/trackpad is scrolled + very slowly.

+ This is a semi-automated test, if you are using a hi-res mouse/trackpad + and it satisfies the hi-res MouseWheelEvents as described below, + the test should automatically pass.

+ + When preciseWheelRotation adds up, wheelRotation becomes non-zero + (can be negative when mouse wheel is scrolled down).
+ You should see many events where the absolute value of + preciseWheelRotation < 1 & wheelRotation = 0 followed by + an event where wheelRotation != 0 in the logs.

+ +
+ NOTE: +
    +
  • If you don't see events with preciseWheelRotation < 1, + then the mouse doesn't support high-resolution scrolling.
  • +
  • A warning is shown if you are not using a hi-res mouse.
  • +
  • MouseWheelEvent logs are displayed in the log area + for user reference.
  • +
  • When mouse is scrolled up, preciseWheelRotation & wheelRotation + are positive and they are negative when scrolled down.
  • +
+ + + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows(30) + .columns(54) + .testTimeOut(10) + .logArea(10) + .testUI(AWTPanelSmoothWheel::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("Test Wheel Rotation"); + Panel panel = new Panel(); + panel.setBackground(Color.GREEN); + panel.addMouseWheelListener(e -> { + if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) { + PassFailJFrame.log("WheelEvent#" + (++wheelEventCount) + + " --- Wheel Rotation: " + e.getWheelRotation() + + " --- Precise Wheel Rotation: " + + String.format("%.2f", e.getPreciseWheelRotation())); + if (Math.abs(e.getPreciseWheelRotation()) < 1) { + hiResWheelCount++; + } + if (wheelEventCount >= 5 && hiResWheelCount == 0) { + PassFailJFrame.log(WARNING_MSG); + JOptionPane.showMessageDialog(frame, WARNING_MSG, + "Warning", JOptionPane.WARNING_MESSAGE); + } + if (e.getWheelRotation() != 0 && hiResWheelCount > 0) { + PassFailJFrame.log("The test passes: hiResWheelCount = " + + hiResWheelCount); + PassFailJFrame.forcePass(); + } + } + }); + frame.setSize(400, 200); + frame.setLayout(new BorderLayout()); + frame.add(panel, BorderLayout.CENTER); + return frame; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/DragMouseEventTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2000, 2025, 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 4327618 4327623 4327639 4327654 4327664 4327666 4327676 4327679 4507822 + * @summary Tests that MouseDragged and MouseReleased are triggered by Button, + * Checkbox, Choice, Label, List, Scrollbar, TextArea, TextField + * for Left, Middle and Right mouse buttons + * @key headful + * @library /lib/client /java/awt/regtesthelpers + * @build ExtendedRobot Util + * @run main/othervm -Dsun.java2d.uiScale=1 DragMouseEventTest +*/ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +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; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Arrays; + +import test.java.awt.regtesthelpers.Util; + +public class DragMouseEventTest { + private static ExtendedRobot robot; + private static DragMouseEventFrame dmef; + private static final int DELAY = 200; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(DragMouseEventTest::createAndShowGUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (dmef != null) { + dmef.dispose(); + } + }); + } + } + + private static void createAndShowGUI() { + dmef = new DragMouseEventFrame(); + dmef.setVisible(true); + } + + private static void test() throws Exception { + robot = new ExtendedRobot(); + robot.waitForIdle(); + robot.delay(500); + + testComponent(dmef.scrollbar); + testComponent(dmef.choice); + testComponent(dmef.textarea); + testComponent(dmef.textfield); + testComponent(dmef.checkbox); + testComponent(dmef.label); + testComponent(dmef.list); + testComponent(dmef.button); + } + + private static void testComponent(Component component) throws Exception { + Rectangle componentBounds = Util.invokeOnEDT(() -> { + Point locationOnScreen = component.getLocationOnScreen(); + Dimension size = component.getSize(); + return new Rectangle(locationOnScreen, size); + }); + + Rectangle frameBounds = Util.invokeOnEDT(() -> dmef.getBounds()); + + Point start = new Point(componentBounds.x + 10, componentBounds.y + 10); + + Adapter adapter = getAdapterFromComponent(component); + + testItemStateChanged(component, adapter, start, componentBounds); + testActionListener(component, adapter, start); + + Point mid = getEndPoint(start, frameBounds, 3); + Point end = getEndPoint(start, frameBounds, 15); + + testButtonDrag(component, adapter, MouseEvent.BUTTON1_DOWN_MASK, start, mid, end); + testButtonDrag(component, adapter, MouseEvent.BUTTON2_DOWN_MASK, start, mid, end); + testButtonDrag(component, adapter, MouseEvent.BUTTON3_DOWN_MASK, start, mid, end); + } + + private static Adapter getAdapterFromComponent(Component component) { + return (Adapter) Arrays + .stream(component.getMouseListeners()) + .filter((m) -> m instanceof Adapter) + .findFirst() + .orElseThrow(); + } + + private static void testItemStateChanged(Component component, + Adapter adapter, + Point start, + Rectangle componentBounds) { + if (!(component instanceof Choice + || component instanceof Checkbox + || component instanceof List)) { + return; + } + + System.out.println("\ntestItemStateChanged " + component); + + adapter.reset(); + robot.mouseMove(start.x, start.y); + robot.waitForIdle(); + robot.click(); + + if (component instanceof Choice) { + robot.mouseMove(start.x, componentBounds.y + componentBounds.height + 25); + robot.waitForIdle(); + robot.click(); + } + + robot.waitForIdle(); + + if (!adapter.itemStateChangedReceived) { + throw new RuntimeException("itemStateChanged was not received for " + component); + } + } + + private static void testActionListener(Component component, + Adapter adapter, + Point start) { + if (!(component instanceof Button || component instanceof List)) { + // skip for not applicable components + return; + } + + System.out.println("\ntestActionListener " + component); + adapter.reset(); + + robot.mouseMove(start.x, start.y); + robot.waitForIdle(); + + if (component instanceof List) { + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(DELAY); + } else { + robot.click(); + } + + robot.waitForIdle(); + robot.delay(DELAY); + + if (!adapter.actionPerformedReceived) { + throw new RuntimeException("actionPerformed was not received for " + component); + } + } + + private static String getButtonName(int button) { + return switch (button) { + case MouseEvent.BUTTON1_DOWN_MASK -> "BUTTON1"; + case MouseEvent.BUTTON2_DOWN_MASK -> "BUTTON2"; + case MouseEvent.BUTTON3_DOWN_MASK -> "BUTTON3"; + default -> throw new IllegalStateException("Unexpected value: " + button); + }; + } + + private static void testButtonDrag(Component component, + Adapter adapter, + int button, + Point start, Point mid, Point end) { + String buttonName = getButtonName(button); + System.out.printf("\n> testButtonDrag: %s on %s\n", + buttonName, component); + + robot.mouseMove(start.x, start.y); + robot.waitForIdle(); + + robot.mousePress(button); + robot.waitForIdle(); + + System.out.printf("> gliding from (%d,%d) to (%d,%d)\n", + start.x, start.y, mid.x, mid.y); + robot.glide(start, mid); + robot.waitForIdle(); + robot.delay(DELAY); + + + // Catch events only after we leave the frame boundaries + adapter.reset(); + + System.out.printf("> gliding after crossing the border (%d,%d) to (%d,%d)\n", + mid.x, mid.y, end.x, end.y); + robot.glide(mid, end); + + robot.mouseRelease(button); + robot.waitForIdle(); + robot.delay(DELAY); + System.out.printf("> %s released\n", buttonName); + + boolean mouseDraggedReceived = adapter.mouseDraggedReceived; + boolean mouseReleasedReceived = adapter.mouseReleasedReceived; + + if (component instanceof Choice) { + // Close the popup if it is still open + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.delay(25); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); + robot.delay(DELAY); + } + + + if (!mouseDraggedReceived || !mouseReleasedReceived) { + throw new RuntimeException(("%d: Mouse drag or release was not received\n" + + "mouseDraggedReceived %b mouseReleasedReceived %b") + .formatted(button, mouseDraggedReceived, mouseReleasedReceived)); + } + } + + /* + * returns the closest border point with a specified offset + */ + private static Point getEndPoint(Point start, Rectangle bounds, int offset) { + int left = bounds.x; + int right = bounds.x + bounds.width; + int top = bounds.y; + int bottom = bounds.y + bounds.height; + + int distanceLeft = start.x - left; + int distanceRight = right - start.x; + int distanceTop = start.y - top; + int distanceBottom = bottom - start.y; + + int minDistance = Math.min( + Math.min(distanceLeft, distanceRight), + Math.min(distanceTop, distanceBottom) + ); + + if (minDistance == distanceLeft) { + return new Point(left - offset, start.y); + } else if (minDistance == distanceRight) { + return new Point(right + offset, start.y); + } else if (minDistance == distanceTop) { + return new Point(start.x, top - offset); + } else { + return new Point(start.x, bottom + offset); + } + } + + private static class DragMouseEventFrame extends Frame { + TextArea textarea = new TextArea("TextArea", 20, 30); + Label label = new Label("Label"); + Panel panel = new Panel(); + List list = new List(); + Choice choice = new Choice(); + Button button = new Button("Button"); + TextField textfield = new TextField("TextField"); + Checkbox checkbox = new Checkbox("CheckBox"); + Scrollbar scrollbar = new Scrollbar(); + Panel centerPanel = new Panel(); + + public DragMouseEventFrame() { + setTitle("DragMouseEventTest"); + + add(centerPanel, BorderLayout.CENTER); + centerPanel.setLayout(new FlowLayout()); + + add(panel, BorderLayout.NORTH); + panel.setLayout(new FlowLayout()); + + choice.add("choice item 1"); + choice.add("choice item 2"); + choice.add("choice item 3"); + panel.add(choice); + + Adapter adapter = new Adapter(); + choice.addMouseMotionListener(adapter); + choice.addMouseListener(adapter); + choice.addItemListener(adapter); + + adapter = new Adapter(); + panel.add(label); + label.addMouseMotionListener(adapter); + label.addMouseListener(adapter); + + adapter = new Adapter(); + panel.add(button); + button.addMouseMotionListener(adapter); + button.addMouseListener(adapter); + button.addActionListener(adapter); + + adapter = new Adapter(); + panel.add(checkbox); + checkbox.addMouseMotionListener(adapter); + checkbox.addMouseListener(adapter); + checkbox.addItemListener(adapter); + + adapter = new Adapter(); + panel.add(textfield, BorderLayout.EAST); + textfield.addMouseMotionListener(adapter); + textfield.addMouseListener(adapter); + textfield.addActionListener(adapter); + + adapter = new Adapter(); + add(textarea, BorderLayout.EAST); + textarea.addMouseMotionListener(adapter); + textarea.addMouseListener(adapter); + + adapter = new Adapter(); + list.add("list item 1"); + list.add("list item 2"); + add(list, BorderLayout.SOUTH); + list.addMouseMotionListener(adapter); + list.addMouseListener(adapter); + list.addActionListener(adapter); + list.addItemListener(adapter); + + adapter = new Adapter(); + add(scrollbar, BorderLayout.WEST); + scrollbar.addMouseMotionListener(adapter); + scrollbar.addMouseListener(adapter); + + setSize(500, 400); + setLocationRelativeTo(null); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + DragMouseEventFrame.this.dispose(); + } + }); + } + } + + private static class Adapter extends MouseAdapter + implements ActionListener, ItemListener { + + public volatile boolean mouseDraggedReceived = false; + public volatile boolean mouseReleasedReceived = false; + public volatile boolean itemStateChangedReceived = false; + public volatile boolean actionPerformedReceived = false; + + + public void mouseDragged(MouseEvent me) { + mouseDraggedReceived = true; + System.out.println(me.paramString()); + } + + private void consumeIfNeeded(MouseEvent me) { + Component c = me.getComponent(); + // do not show popup menu for the following components, + // as it may interfere with the testing. + if (c instanceof TextArea + || c instanceof TextField + || c instanceof Scrollbar) { + if (me.isPopupTrigger()) { + System.out.println("CONSUMED: " + me); + me.consume(); + } + } + } + + public void mouseReleased(MouseEvent me) { + consumeIfNeeded(me); + mouseReleasedReceived = true; + System.out.println(me.paramString()); + } + + public void mousePressed(MouseEvent me) { + consumeIfNeeded(me); + System.out.println(me.paramString()); + } + + public void mouseClicked(MouseEvent me) { + System.out.println(me.paramString()); + } + + public void actionPerformed(ActionEvent e) { + actionPerformedReceived = true; + System.out.println(e.paramString()); + } + + public void itemStateChanged(ItemEvent e) { + itemStateChangedReceived = true; + System.out.println(e.paramString()); + } + + public void reset() { + mouseDraggedReceived = false; + mouseReleasedReceived = false; + itemStateChangedReceived = false; + actionPerformedReceived = false; + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/DragToLightweightTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/DragToLightweightTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/DragToLightweightTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/DragToLightweightTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001, 2025, 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 4417964 + * @summary tests that drag events continue to arrive to heavyweight + * when the mouse is moved to lightweight while dragging. + * @key headful + * @library /lib/client /java/awt/regtesthelpers + * @build ExtendedRobot Util + * @run main DragToLightweightTest +*/ + +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.HeadlessException; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import test.java.awt.regtesthelpers.Util; + +public class DragToLightweightTest { + + private static final CountDownLatch latch = new CountDownLatch(1); + private static volatile MouseTest mouseTest; + + public static void main(String[] args) throws Exception { + + EventQueue.invokeAndWait(() -> mouseTest = new MouseTest()); + + try { + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (mouseTest != null) { + mouseTest.dispose(); + } + }); + } + } + + private static void test() throws Exception { + ExtendedRobot robot = new ExtendedRobot(); + robot.waitForIdle(); + robot.delay(500); + + Rectangle componentBounds = mouseTest.getLightweightComponentBounds(); + + robot.dragAndDrop( + componentBounds.x + componentBounds.width / 2, componentBounds.y + componentBounds.height + 30, + componentBounds.x + componentBounds.width / 2, componentBounds.y + 2 * componentBounds.height / 3 + ); + + if (!latch.await(5, TimeUnit.SECONDS)) { + throw new RuntimeException("The test failed: no mouse release event received"); + } + + System.out.println("Mouse release event received, the test PASSED"); + } + + private static class MouseTest extends Frame { + + final Foo foo; + + public MouseTest() throws HeadlessException { + super("DragToLightweightTest"); + + setLayout(new FlowLayout()); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseReleased(MouseEvent e) { + System.out.println("mouseReleased"); + latch.countDown(); + } + }); + + // Create a Component that will be a child of the Frame and add + // a MouseListener to it. + foo = new Foo(); + foo.setBackground(Color.red); + + System.out.println(foo.getPreferredSize()); + foo.setPreferredSize(new Dimension(350, 200)); + System.out.println(foo.getPreferredSize()); + + foo.addMouseListener(new DummyAdapter()); + + add(foo); + + setSize(400, 400); + setLocationRelativeTo(null); + setVisible(true); + } + + public Rectangle getLightweightComponentBounds() throws Exception { + return Util.invokeOnEDT(() -> { + Point locationOnScreen = foo.getLocationOnScreen(); + Dimension size = foo.getSize(); + return new Rectangle(locationOnScreen.x, locationOnScreen.y, size.width, size.height); + }); + } + + private static class Foo extends Container { + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + g.setColor(Color.white); + g.drawString(getBounds().toString(), 5, 20); + super.paint(g); + } + } + + private static class DummyAdapter extends MouseAdapter {} + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/MouseEnterTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseEnterTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/MouseEnterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseEnterTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2002, 2025, 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 4095172 + * @summary Test for no proper mouse coordinates on MOUSE_ENTER/MOUSE_EXIT events for Win boxes. + * @key headful + * @library /lib/client /java/awt/regtesthelpers + * @build ExtendedRobot Util + * @run main MouseEnterTest + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +import test.java.awt.regtesthelpers.Util; + +public class MouseEnterTest { + private static Frame frame; + private static final TestMouseAdapter mouseAdapter = new TestMouseAdapter(); + + public static void main(String[] args) throws Exception { + EventQueue.invokeAndWait(MouseEnterTest::initAndShowGUI); + try { + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void initAndShowGUI() { + frame = new Frame("MouseEnterTest"); + frame.setLayout(null); + frame.setSize(300, 200); + frame.setLocationRelativeTo(null); + frame.addMouseListener(mouseAdapter); + frame.setVisible(true); + } + + private static void test() throws Exception { + ExtendedRobot robot = new ExtendedRobot(); + robot.waitForIdle(); + robot.delay(500); + + Rectangle bounds = Util.invokeOnEDT(frame::getBounds); + + java.util.List points = getBorderGlidePoints(bounds); + for (int i = 0; i < points.size(); i += 2) { + Point p1 = points.get(i); + Point p2 = points.get(i + 1); + + System.out.println("\n------------------\n"); + + System.out.printf("%s > %s > %s\n", p1, p2, p1); + robot.glide(p1, p2); + robot.waitForIdle(); + robot.glide(p2, p1); + robot.waitForIdle(); + robot.delay(200); + mouseAdapter.testEvents(); + + System.out.println("\n------------------\n"); + + System.out.printf("%s > %s > %s\n", p2, p1, p2); + robot.glide(p2, p1); + robot.waitForIdle(); + robot.glide(p1, p2); + robot.waitForIdle(); + robot.delay(200); + mouseAdapter.testEvents(); + } + } + + private static java.util.List getBorderGlidePoints(Rectangle bounds) { + java.util.List list = new ArrayList<>(); + + int d = 10; + + // left + list.add(new Point(bounds.x - d, bounds.y + bounds.height / 2)); + list.add(new Point(bounds.x + d, bounds.y + bounds.height / 2)); + + // right + list.add(new Point(bounds.x + bounds.width - d, bounds.y + bounds.height / 2)); + list.add(new Point(bounds.x + bounds.width + d, bounds.y + bounds.height / 2)); + + // top + list.add(new Point(bounds.x + bounds.width / 2, bounds.y - d)); + list.add(new Point(bounds.x + bounds.width / 2, bounds.y + d)); + + // bottom + list.add(new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height - d)); + list.add(new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height + d)); + + return list; + } + + private static final class TestMouseAdapter extends MouseAdapter { + private static final int THRESHOLD = 5; + private volatile MouseEvent lastEnteredEvent = null; + private volatile MouseEvent lastExitedEvent = null; + + @Override + public void mouseEntered(MouseEvent e) { + System.out.println("MouseEntered " + e); + lastEnteredEvent = e; + } + + @Override + public void mouseExited(MouseEvent e) { + System.out.println("MouseExited " + e); + lastExitedEvent = e; + } + + public void testEvents() { + if (lastEnteredEvent == null || lastExitedEvent == null) { + throw new RuntimeException("Missing lastEnteredEvent or lastExitedEvent"); + } + + System.out.println("\nTesting:"); + System.out.println(lastEnteredEvent); + System.out.println(lastExitedEvent); + System.out.println(); + + int diffX = Math.abs(lastEnteredEvent.getX() - lastExitedEvent.getX()); + int diffScreenX = Math.abs(lastEnteredEvent.getY() - lastExitedEvent.getY()); + int diffY = Math.abs(lastEnteredEvent.getXOnScreen() - lastExitedEvent.getXOnScreen()); + int diffScreenY = Math.abs(lastEnteredEvent.getYOnScreen() - lastExitedEvent.getYOnScreen()); + + System.out.printf("THRESHOLD %d, diffX %d diffScreenX %d " + + "diffY %d diffScreenY %d\n", + THRESHOLD, + diffX, diffScreenX, + diffY, diffScreenY + ); + + if (diffX > THRESHOLD + || diffScreenX > THRESHOLD + || diffY > THRESHOLD + || diffScreenY > THRESHOLD) { + throw new RuntimeException("Mouse enter vs exit event is too different"); + } + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseEventsDuringDrag.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,307 @@ +/* + * Copyright (c) 1999, 2025, 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 4017222 + * @summary Checks whether mouse events are reported correctly during drag. + * @author Stuart Lawrence, Brent Christian: area=event + * @key headful + * @library /lib/client /java/awt/regtesthelpers + * @build ExtendedRobot Util + * @run main MouseEventsDuringDrag + */ + + +/* + * MouseEventsDuringDrag.java + * + * summary: + * On Solaris drag enter/exit events are only reported for the + * component where drag started, they're not reported on other + * components. On Win32 enter/exit events are reported correctly. + */ + +import test.java.awt.regtesthelpers.Util; + +import java.awt.Canvas; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class MouseEventsDuringDrag { + + private static ExtendedRobot robot; + private static Frame frame; + + private static final MouseHandler mouseHandler = new MouseHandler(); + + static Label lab; + static Canvas c1, c2; + static Choice choice; + + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(MouseEventsDuringDrag::createAndShowGUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void test() throws Exception { + robot = new ExtendedRobot(); + robot.waitForIdle(); + robot.delay(500); + + // Part 1: Press and hold down the mouse button inside the red box. + // Drag the mouse over to the blue box (whilst still holding down + // the mouse button). + // Whilst dragging the mouse from the red box, enter and exit + // events should be reported for the blue box. + testcase(c2, "c1 to c2"); + + // Part 2: Again, press and hold down the mouse button inside the red box. + // This time drag the mouse over to the Choice menu. + // Enter and exit events should be reported for the Choice menu. + testcase(choice, "c1 to choice"); + } + + private static void testcase(Component moveTo, String message) throws Exception { + System.out.println("\ntestcase: " + message); + Rectangle c1bounds = getBounds(c1); + Rectangle moveToBound = getBounds(moveTo); + + Point startDragLocation = + new Point(c1bounds.x + c1bounds.width - 10, + c1bounds.y + c1bounds.height / 2); + + Point endDragLocation = + new Point(moveToBound.x + 10, moveToBound.y + moveToBound.height / 2); + + robot.mouseMove(startDragLocation); + robot.waitForIdle(); + robot.delay(200); + mouseHandler.reset(); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + robot.glide(startDragLocation, endDragLocation); + robot.waitForIdle(); + + robot.glide(endDragLocation.x, endDragLocation.y, endDragLocation.x - 20, endDragLocation.y); + + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.waitForIdle(); + robot.delay(200); + + List actual = mouseHandler.getRecordedEvents(); + + List expected = List.of( + new EventRecord(MouseEvent.MOUSE_PRESSED, c1), + new EventRecord(MouseEvent.MOUSE_EXITED, c1), + new EventRecord(MouseEvent.MOUSE_ENTERED, moveTo), + new EventRecord(MouseEvent.MOUSE_EXITED, moveTo), + new EventRecord(MouseEvent.MOUSE_RELEASED, c1) + ); + + System.out.println("Expected:\n" + expected); + System.out.println("Actual:\n" + actual); + if (!actual.equals(expected)) { + throw new RuntimeException("Mismatch between expected and actual events\n%s\n%s" + .formatted(expected, actual)); + } + } + + private static Rectangle getBounds(Component c) throws Exception { + return Util.invokeOnEDT(() -> { + Point locationOnScreen = c.getLocationOnScreen(); + Dimension size = c.getSize(); + return new Rectangle(locationOnScreen.x, locationOnScreen.y, size.width, size.height); + }); + } + + private static void createAndShowGUI() { + frame = new Frame(); + MouseHandler mouseHandler = new MouseHandler(); + frame.setLayout(new GridBagLayout()); + + int canvasSize = 100; + c1 = new Canvas(); + c1.setPreferredSize(new Dimension(canvasSize, canvasSize)); + c1.setBackground(Color.red); + c1.addMouseListener(mouseHandler); + + c2 = new Canvas(); + c2.setPreferredSize(new Dimension(canvasSize, canvasSize)); + c2.setBackground(Color.blue); + c2.addMouseListener(mouseHandler); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(5, 5, 5, 5); + + gbc.gridx = 0; + gbc.gridy = 0; + frame.add(c1, gbc); + + gbc.gridx = 2; + frame.add(c2, gbc); + + Panel p1 = new Panel(); + p1.setLayout(new FlowLayout()); + choice = new Choice(); + choice.addItem("Choice"); + choice.addItem("One"); + choice.addItem("Two"); + choice.addMouseListener(mouseHandler); + p1.add(choice); + + gbc.gridx = 1; + gbc.gridy = 1; + frame.add(p1, gbc); + + lab = new Label(); + + gbc.gridx = 0; + gbc.gridy = 2; + gbc.gridwidth = 3; + frame.add(lab, gbc); + + frame.pack(); + frame.setLocationRelativeTo(null); + + frame.setVisible(true); + } + + record EventRecord(int eventId, Component component) { + + @Override + public String toString() { + StringBuilder str = new StringBuilder(80); + switch(eventId) { + case MouseEvent.MOUSE_PRESSED: + str.append("MOUSE_PRESSED"); + break; + case MouseEvent.MOUSE_RELEASED: + str.append("MOUSE_RELEASED"); + break; + case MouseEvent.MOUSE_CLICKED: + str.append("MOUSE_CLICKED"); + break; + case MouseEvent.MOUSE_ENTERED: + str.append("MOUSE_ENTERED"); + break; + case MouseEvent.MOUSE_EXITED: + str.append("MOUSE_EXITED"); + break; + case MouseEvent.MOUSE_MOVED: + str.append("MOUSE_MOVED"); + break; + case MouseEvent.MOUSE_DRAGGED: + str.append("MOUSE_DRAGGED"); + break; + case MouseEvent.MOUSE_WHEEL: + str.append("MOUSE_WHEEL"); + break; + default: + str.append("unknown type"); + } + return str.append(" ").append(component).toString(); + } + } + + static class MouseHandler extends MouseAdapter { + static final List list = new CopyOnWriteArrayList<>(); + + public void mousePressed(MouseEvent e) { + list.add(new EventRecord(e.getID(), e.getComponent())); + if (e.getSource() == c1) { + lab.setText("Mouse pressed in red box"); + } else if (e.getSource() == c2) { + lab.setText("Mouse pressed in blue box"); + } else if (e.getSource() == choice) { + lab.setText("Mouse pressed in choice"); + } + } + + public void mouseReleased(MouseEvent e) { + list.add(new EventRecord(e.getID(), e.getComponent())); + lab.setText("Mouse released"); + } + + public void mouseEntered(MouseEvent e) { + list.add(new EventRecord(e.getID(), e.getComponent())); + if (e.getSource() == c1) { + lab.setText("Mouse entered red box"); + } else if (e.getSource() == c2) { + lab.setText("Mouse entered blue box"); + } else if (e.getSource() == choice) { + lab.setText("Mouse entered choice"); + } + } + + public void mouseExited(MouseEvent e) { + list.add(new EventRecord(e.getID(), e.getComponent())); + if (e.getSource() == c1) { + lab.setText("Mouse exited red box"); + } else if (e.getSource() == c2) { + lab.setText("Mouse exited blue box"); + } else if (e.getSource() == choice) { + lab.setText("Mouse exited choice"); + } + } + + public void reset() { + list.clear(); + } + + public List getRecordedEvents() { + return new ArrayList<>(list); + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseModifierTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1999, 2025, 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 4117523 + * @summary Solaris: MousePressed event has modifier=0 when left button is pressed + * @key headful + * @library /javax/swing/regtesthelpers /test/lib + * @build Util jdk.test.lib.Platform + * @run main MouseModifierTest +*/ + + +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.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import jdk.test.lib.Platform; + +public class MouseModifierTest { + private static Frame frame; + private static volatile MouseEvent lastMousePressedEvent = null; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(MouseModifierTest::createAndShowGUI); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void test() throws Exception { + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(500); + + Point centerPoint = Util.getCenterPoint(frame); + + System.out.println("MOUSE1 press case"); + + robot.mouseMove(centerPoint.x, centerPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(300); + + if (lastMousePressedEvent == null + || lastMousePressedEvent.getModifiers() != InputEvent.BUTTON1_MASK) { + throw new RuntimeException("Test failed"); + } + + if (Platform.isWindows()) { + System.out.println("Windows: Testing ALT + MOUSE1 press case"); + lastMousePressedEvent = null; + robot.waitForIdle(); + robot.delay(300); + + robot.keyPress(KeyEvent.VK_ALT); + robot.delay(25); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(25); + robot.keyRelease(KeyEvent.VK_ALT); + robot.delay(25); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(300); + + int expectedModifiers = InputEvent.BUTTON1_MASK + | InputEvent.BUTTON2_MASK + | InputEvent.ALT_MASK; + if (lastMousePressedEvent == null + || lastMousePressedEvent.getModifiers() != expectedModifiers) { + throw new RuntimeException("Test failed"); + } + } + } + + private static void createAndShowGUI() { + frame = new Frame("MouseModifierTest"); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.addMouseListener(new MouseHandler()); + frame.setVisible(true); + } + + private static class MouseHandler extends MouseAdapter { + public void mouseClicked(MouseEvent e) { + System.out.println("\nmouseClicked:"); + printMouseEventDetail(e); + } + + public void mousePressed(MouseEvent e) { + lastMousePressedEvent = e; + System.out.println("\nmousePressed:"); + printMouseEventDetail(e); + } + + public void mouseReleased(MouseEvent e) { + System.out.println("\nmouseReleased:"); + printMouseEventDetail(e); + } + + public void mouseEntered(MouseEvent e) { + System.out.println("\nmouseEntered:"); + printMouseEventDetail(e); + } + + public void mouseExited(MouseEvent e) { + System.out.println("\nmouseExited:"); + printMouseEventDetail(e); + } + + private void printMouseEventDetail(MouseEvent e) { + System.out.println(e.toString()); + System.out.println("Modifiers: "); + printModifiers(e); + } + + private void printModifiers(MouseEvent e) { + if (e == null) { + return; + } + + int mod = e.getModifiers(); + + if ((mod & InputEvent.ALT_MASK) != 0) { + System.out.println("\tALT_MASK"); + } + if ((mod & InputEvent.BUTTON1_MASK) != 0) { + System.out.println("\tBUTTON1_MASK"); + } + if ((mod & InputEvent.BUTTON2_MASK) != 0) { + System.out.println("\tBUTTON2_MASK"); + } + if ((mod & InputEvent.BUTTON3_MASK) != 0) { + System.out.println("\tBUTTON3_MASK"); + } + if ((mod & InputEvent.CTRL_MASK) != 0) { + System.out.println("\tCTRL_MASK"); + } + if ((mod & InputEvent.META_MASK) != 0) { + System.out.println("\tMETA_MASK"); + } + if ((mod & InputEvent.SHIFT_MASK) != 0) { + System.out.println("\tSHIFT_MASK"); + } + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/MouseRButTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseRButTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/MouseRButTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/MouseRButTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1998, 2025, 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 4037521 + * @summary Mouse Right button does not send mouseClick action + * @key headful + * @library /javax/swing/regtesthelpers + * @build Util + * @run main MouseRButTest + */ + +import java.awt.Button; +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.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class MouseRButTest { + private static Frame frame; + private static Button button; + private static final CountDownLatch latch = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(MouseRButTest::createAndShowGUI); + + robot.waitForIdle(); + robot.delay(500); + + Point point = Util.getCenterPoint(button); + robot.mouseMove(point.x, point.y); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.delay(50); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + if (!latch.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("mouse click action was not sent"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowGUI() { + button = new Button("Click Me"); + button.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + System.out.println(e); + if (e.getModifiers() == e.BUTTON3_MASK) { + System.out.println("right mouse button clicked"); + latch.countDown(); + } + } + }); + + frame = new Frame(); + frame.setLayout(new FlowLayout()); + frame.add(button); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/MouseEvent/TitleBarGetsMousePressed.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999, 2025, 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.Window; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4074498 + * @summary Test: MOUSE_PRESSED events in the title bar of a frame + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TitleBarGetsMousePressed + */ +public class TitleBarGetsMousePressed { + private static final String INSTRUCTIONS = """ + 1. You will see a Frame window next to this window with instructions + 2. Clicking in the title bar of the Frame and even moving around the Frame + should not generate MOUSE_PRESSED / MOUSE_RELEASED / MOUSE_CLICKED events. + (printed below in the log area). + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TitleBarGetsMousePressed Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(TitleBarGetsMousePressed::createTestUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + private static Window createTestUI() { + Frame frame = new Frame("TitleBarGetsMousePressed"); + frame.setSize(300, 200); + frame.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent ev) { + PassFailJFrame.log("mouseClicked at x:" + ev.getX() + + " y:" + ev.getY()); + } + + public void mousePressed(MouseEvent ev) { + PassFailJFrame.log("mousePressed at x:" + ev.getX() + + " y:" + ev.getY()); + } + + public void mouseReleased(MouseEvent ev) { + PassFailJFrame.log("mouseReleased at x:" + ev.getX() + + " y:" + ev.getY()); + } + }); + + return frame; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/StressTest/LargeAWTEventMulticasterTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/StressTest/LargeAWTEventMulticasterTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/StressTest/LargeAWTEventMulticasterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/StressTest/LargeAWTEventMulticasterTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * 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. + */ + +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; +import java.awt.AWTEventMulticaster; + +/* + * @test + * @bug 8342782 + * @summary Tests large AWTEventMulticasters for StackOverflowErrors + * @run main LargeAWTEventMulticasterTest + */ +public class LargeAWTEventMulticasterTest { + + /** + * This is an empty ActionListener that also has a numeric index. + */ + static class IndexedActionListener implements ActionListener { + private final int index; + + public IndexedActionListener(int index) { + this.index = index; + } + + @Override + public void actionPerformed(ActionEvent e) { + + } + + public int getIndex() { + return index; + } + + @Override + public String toString() { + return Integer.toString(index); + } + } + + public static void main(String[] args) { + int maxA = 0; + try { + for (int a = 1; a < 200_000; a *= 2) { + maxA = a; + testAddingActionListener(a); + } + } finally { + System.out.println("maximum a = " + maxA); + } + } + + private static void testAddingActionListener(int numberOfListeners) { + // step 1: create the large AWTEventMulticaster + ActionListener l = null; + for (int a = 0; a < numberOfListeners; a++) { + l = AWTEventMulticaster.add(l, new IndexedActionListener(a)); + } + + // Prior to 8342782 we could CREATE a large AWTEventMulticaster, but we couldn't + // always interact with it. + + // step 2: dispatch an event + // Here we're making sure we don't get a StackOverflowError when we traverse the tree: + l.actionPerformed(null); + + // step 3: make sure getListeners() returns elements in the correct order + // The resolution for 8342782 introduced a `rebalance` method; we want to + // double-check that the rebalanced tree preserves the appropriate order. + IndexedActionListener[] array = AWTEventMulticaster.getListeners(l, IndexedActionListener.class); + for (int b = 0; b < array.length; b++) { + if (b != array[b].getIndex()) + throw new Error("the listeners are in the wrong order. " + b + " != " + array[b].getIndex()); + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/event/WindowActivatedEventTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/event/WindowActivatedEventTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/event/WindowActivatedEventTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/event/WindowActivatedEventTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 1999, 2025, 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 4219344 + * @summary tests that WINDOW_ACTIVATED events are generated properly + * @key headful + * @library /test/jdk/java/awt/regtesthelpers + * @build Util + * @run main WindowActivatedEventTest + */ + +import test.java.awt.regtesthelpers.Util; + +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Window; +import java.awt.event.WindowEvent; +import java.awt.event.WindowAdapter; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; + +public class WindowActivatedEventTest { + + static Robot robot; + static Frame frame; + static Dialog dialog; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + try { + EventQueue.invokeAndWait(WindowActivatedEventTest::createAndShowGUI); + robot.waitForIdle(); + robot.delay(500); + + Util.clickOnComp(dialog, robot); + + robot.waitForIdle(); + robot.delay(500); + + for (int i = 0; i < 3 ; i++) { + clickAndCheck(frame); + clickAndCheck(dialog); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + if (dialog != null) { + dialog.dispose(); + } + }); + } + } + + private static void clickAndCheck(Window windowToFocus) + throws InterruptedException, InvocationTargetException { + Window oppositeWindow = (windowToFocus == frame) ? dialog : frame; + + System.out.println("Clicking on " + windowToFocus); + + EventQueue.invokeAndWait(() -> { + if (windowToFocus.isFocused() || !oppositeWindow.isFocused()) { + throw new RuntimeException("%s isFocused %b, %s isFocused %b".formatted( + windowToFocus.getName(), windowToFocus.isFocused(), + oppositeWindow.getName(), oppositeWindow.isFocused() + )); + } + }); + + WindowEventLogger windowLogger = WindowEventLogger.getFromWindow(windowToFocus); + WindowEventLogger oppositeWindowLogger = WindowEventLogger.getFromWindow(oppositeWindow); + + windowLogger.resetCounters(); + oppositeWindowLogger.resetCounters(); + + Util.clickOnComp(windowToFocus, robot); + + robot.delay(500); + + int windowActivatedCount = windowLogger.activatedCount.get(); + int windowDeactivatedCount = windowLogger.deactivatedCount.get(); + int oppositeWindowActivatedCount = oppositeWindowLogger.activatedCount.get(); + int oppositeWindowDeactivatedCount = oppositeWindowLogger.deactivatedCount.get(); + + if (windowActivatedCount != 1 + || windowDeactivatedCount != 0 + || oppositeWindowActivatedCount != 0 + || oppositeWindowDeactivatedCount != 1) { + throw new RuntimeException( + "Invalid activated/deactivated count: %s (%d/%d) / %s (%d/%d)" + .formatted( + windowToFocus.getName(), + windowActivatedCount, + windowDeactivatedCount, + oppositeWindow.getName(), + oppositeWindowActivatedCount, + oppositeWindowDeactivatedCount + )); + } + } + + private static void createAndShowGUI() { + frame = new Frame("frame WindowActivatedEventTest"); + dialog = new Dialog(frame, "dialog WindowActivatedEventTest"); + + frame.addWindowListener(new WindowEventLogger()); + dialog.addWindowListener(new WindowEventLogger()); + + frame.setBounds(400, 0, 200, 200); + frame.setVisible(true); + + dialog.setBounds(400, 200, 200, 200); + dialog.setVisible(true); + } + + private static class WindowEventLogger extends WindowAdapter { + final AtomicInteger activatedCount = new AtomicInteger(0); + final AtomicInteger deactivatedCount = new AtomicInteger(0); + + public void windowActivated(WindowEvent e) { + activatedCount.incrementAndGet(); + System.out.println(e); + } + + public void windowDeactivated(WindowEvent e) { + deactivatedCount.incrementAndGet(); + System.out.println(e); + } + + public void resetCounters() { + activatedCount.set(0); + deactivatedCount.set(0); + } + + public static WindowEventLogger getFromWindow(Window window) { + return (WindowEventLogger) Arrays + .stream(window.getWindowListeners()) + .filter(listener -> listener instanceof WindowEventLogger) + .findFirst().get(); + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/font/TextLayout/MyanmarTextTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/font/TextLayout/MyanmarTextTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/font/TextLayout/MyanmarTextTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/font/TextLayout/MyanmarTextTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -27,12 +27,15 @@ * @key headful * @summary Verifies that Myanmar script is rendered correctly: * two characters combined into one glyph + * @library /test/lib + * @build jtreg.SkippedException * @run main MyanmarTextTest */ import java.awt.Font; import java.awt.GraphicsEnvironment; import java.util.Arrays; +import java.util.List; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JFrame; @@ -45,12 +48,16 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Position; +import jtreg.SkippedException; + public class MyanmarTextTest { private static final String TEXT = "\u1000\u103C"; - private static final String FONT_WINDOWS = "Myanmar Text"; - private static final String FONT_LINUX = "Padauk"; - private static final String FONT_MACOS = "Myanmar MN"; + private static final List FONT_CANDIDATES = + List.of("Myanmar MN", + "Padauk", + "Myanmar Text", + "Noto Sans Myanmar"); private static final String FONT_NAME = selectFontName(); @@ -61,12 +68,8 @@ public static void main(String[] args) throws Exception { if (FONT_NAME == null) { - System.err.println("Unsupported OS: exiting"); - return; - } - if (!fontExists()) { - System.err.println("Required font is not installed: " + FONT_NAME); - return; + throw new SkippedException("No suitable font found out of the list: " + + String.join(", ", FONT_CANDIDATES)); } try { @@ -130,22 +133,12 @@ } private static String selectFontName() { - String osName = System.getProperty("os.name").toLowerCase(); - if (osName.contains("windows")) { - return FONT_WINDOWS; - } else if (osName.contains("linux")) { - return FONT_LINUX; - } else if (osName.contains("mac")) { - return FONT_MACOS; - } else { - return null; - } + return Arrays.stream(GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getAvailableFontFamilyNames()) + .filter(FONT_CANDIDATES::contains) + .findFirst() + .orElse(null); } - private static boolean fontExists() { - String[] fontFamilyNames = GraphicsEnvironment - .getLocalGraphicsEnvironment() - .getAvailableFontFamilyNames(); - return Arrays.asList(fontFamilyNames).contains(FONT_NAME); - } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/4490692/bug4490692.html openjdk-21-21.0.9+10/test/jdk/java/awt/im/4490692/bug4490692.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/4490692/bug4490692.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/4490692/bug4490692.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ - - - - - - Test for KEY_PRESS event for accented characters - - - -

Test for KEY_PRESS event for accented characters: Bug id 4490692

- -This test is for unix platforms only. Press OK if you are not -testing on those platforms. - -Before the test, you need to modify the keyboard mapping for X by issueing -the following command: - -xmodmap -e 'keycode 60 = aacute' (this is for Solaris Sparc keyboard) -xmodmap -e 'keycode 23 = aacute' (this is for Linux PC keyboard) - -This command lets you type 'a with acute' character when you press 'Tab' keytop. Please -do not fail to restore the original key mapping by doing the following after the test - -xmodmap -e 'keycode 60 = Tab' (this is for Solaris Sparc keyboard) -xmodmap -e 'keycode 23 = Tab' (this is for Linux PC keyboard) - -Confirm the following two behaviors: - - "KEYPRESS received for aacute" is displayed when you press 'Tab' keytop. - On Solaris Sparc keyboard, The key sequence ("Compose", "a", "'") generates a-acute character in en_US locale - - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/4490692/bug4490692.java openjdk-21-21.0.9+10/test/jdk/java/awt/im/4490692/bug4490692.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/4490692/bug4490692.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/4490692/bug4490692.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2007, 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. - */ - -/** - * - * @bug 4490692 - * @author Naoto Sato - */ - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; - -public class bug4490692 extends javax.swing.JApplet { - public void init() { - new TestFrame(); - } -} - -class TestFrame extends JFrame implements KeyListener { - JTextField text; - JLabel label; - - TestFrame () { - text = new JTextField(); - text.addKeyListener(this); - label = new JLabel(" "); - Container c = getContentPane(); - BorderLayout borderLayout1 = new BorderLayout(); - c.setLayout(borderLayout1); - c.add(text, BorderLayout.CENTER); - c.add(label, BorderLayout.SOUTH); - setSize(300, 200); - setVisible(true); - } - - public void keyPressed(KeyEvent e) { - if (e.getKeyChar() == 0x00e1) { - label.setText("KEYPRESS received for aacute"); - } else { - label.setText(" "); - } - } - - public void keyTyped(KeyEvent e) { - } - - public void keyReleased(KeyEvent e) { - } -} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/8132503/bug8132503.html openjdk-21-21.0.9+10/test/jdk/java/awt/im/8132503/bug8132503.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/8132503/bug8132503.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/8132503/bug8132503.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ - - - - -Verify that Chinese full stop symbol can be entered in JTextArea with Pinyin input method (IM). - -This test is for OS X only. For other platforms please simply press "Pass". - -1. Go to "System Preferences -> Keyboard -> Input Sources" and add "Pinyin – Traditional" or "Pinyin – Simplified" IM from Chinese language group. -2. Set current IM to "Pinyin". -3. Set focus to the text area of the test and press "dot" character on the keyboard. -4. Set current IM to the IM used before "Pinyin" was set. -5. If "。" character is displayed in the text area, press "Pass", if "." character is displayed, press "Fail". - - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/8132503/bug8132503.java openjdk-21-21.0.9+10/test/jdk/java/awt/im/8132503/bug8132503.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/8132503/bug8132503.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/8132503/bug8132503.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2015, 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 8132503 - @summary [macosx] Chinese full stop symbol cannot be entered with Pinyin IM on OS X - @author Anton Litvinov - @run applet/manual=yesno bug8132503.html - */ - -import javax.swing.JApplet; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.SwingUtilities; - -public class bug8132503 extends JApplet { - @Override - public void init() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JTextArea textArea = new JTextArea("Text area of the test.", 40, 40); - add(new JScrollPane(textArea)); - } - }); - } -} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/8148984/bug8148984.html openjdk-21-21.0.9+10/test/jdk/java/awt/im/8148984/bug8148984.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/8148984/bug8148984.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/8148984/bug8148984.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ - - - - -Verify that Chinese comma can be entered in JTextField with Pinyin input method (IM). - -This test is for OS X only. For other platforms please simply press "Pass". - -1. Go to "System Preferences -> Keyboard -> Input Sources" and add "Pinyin – Traditional" or "Pinyin – Simplified" IM from Chinese language group. -2. Set current IM to "Pinyin". -3. Set focus to the text field of the test and press "comma" character on the keyboard. -4. Set current IM to the IM used before "Pinyin" was set. -5. If "," character is displayed in the text area, press "Pass", if "," character is displayed, press "Fail". - - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/8148984/bug8148984.java openjdk-21-21.0.9+10/test/jdk/java/awt/im/8148984/bug8148984.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/8148984/bug8148984.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/8148984/bug8148984.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2016, 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 8148984 - * @summary Chinese Comma cannot be entered using Pinyin Input Method on OS X - * @author Dmitry Markov - * @run applet/manual=yesno bug8148984.html - */ - -import javax.swing.*; - -public class bug8148984 extends JApplet { - @Override - public void init() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JPanel panel = new JPanel(); - panel.add(new JLabel("Text field:")); - panel.add(new JTextField(20)); - add(panel); - } - }); - } -} - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/8154816/bug8154816.html openjdk-21-21.0.9+10/test/jdk/java/awt/im/8154816/bug8154816.html --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/8154816/bug8154816.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/8154816/bug8154816.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ - - - - -Verify that Caps Lock key works properly with Pinyin input method, (i.e. if -Caps Lock is pressed, input should be swithced to lowercase latin letters). - -This test is for OS X only. For other platforms please simply press "Pass". - -1. Go to "System Preferences -> Keyboard -> Input Sources" and add "Pinyin – Traditional" or "Pinyin – Simplified" IM from Chinese language group. -2. Set current IM to "Pinyin". -3. Set focus to the text field of the test and press Caps Lock key on the keyboard. -4. Press "a" character on the keyboard -5. If "a" character is displayed in the text field, press "Pass", if "A" character is displayed, press "Fail". - - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/8154816/bug8154816.java openjdk-21-21.0.9+10/test/jdk/java/awt/im/8154816/bug8154816.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/8154816/bug8154816.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/8154816/bug8154816.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2016, 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 8154816 - * @summary Caps Lock doesn't work as expected when using Pinyin Simplified input method - * @author Dmitry Markov - * @run applet/manual=yesno bug8154816.html - */ - -import javax.swing.*; - -public class bug8154816 extends JApplet { - @Override - public void init() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JPanel panel = new JPanel(); - panel.add(new JLabel("Text field:")); - panel.add(new JTextField(20)); - add(panel); - } - }); - } -} - diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/PinyinIMCapsTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMCapsTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/PinyinIMCapsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMCapsTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, 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.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import jtreg.SkippedException; +import sun.awt.OSInfo; + +/* + * @test + * @bug 8154816 + * @summary Caps Lock doesn't work as expected when using Pinyin Simplified input method + * @requires (os.family == "mac") + * @modules java.desktop/sun.awt + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException Util + * @run main/manual PinyinIMCapsTest + */ + +public class PinyinIMCapsTest { + private static final String INSTRUCTIONS = """ + The test verifies if the Caps Lock key works properly with Pinyin + input method, (i.e. if Caps Lock is pressed, input should be + switched to lowercase latin letters). + + Test settings: + Go to "System Preferences -> Keyboard -> Input Sources" and + add "Pinyin – Traditional" or "Pinyin – Simplified" IM from Chinese language group. + Set current IM to "Pinyin". + + 1. Set focus to the text field shown below and press Caps Lock key on the keyboard. + 2. Press "a" character on the keyboard + 3. If "a" character is displayed in the text field, press "Pass", + if "A" character is displayed, press "Fail". + """; + + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.MACOSX) { + throw new SkippedException("This test is for MacOS only"); + } + PassFailJFrame.builder() + .title("Test Pinyin Input Method") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(45) + .splitUIBottom(PinyinIMCapsTest::createUI) + .testTimeOut(10) + .build() + .awaitAndCheck(); + } + + private static JComponent createUI() { + JPanel panel = new JPanel(); + JTextField input = new JTextField(20); + panel.add(new JLabel("Text field:")); + panel.add(input); + return panel; + } +} + diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/PinyinIMCommaTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMCommaTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/PinyinIMCommaTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMCommaTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, 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.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +/* + * @test + * @bug 8148984 + * @summary Verify that Chinese comma can be entered in JTextField + * with Pinyin input method (IM) on OS X. + * @requires (os.family == "mac") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PinyinIMCommaTest + */ + +public class PinyinIMCommaTest { + private static final String INSTRUCTIONS = """ + This test verifies if Chinese comma can be entered in JTextField + with Pinyin input method (IM). + + Test settings: + Go to "System Preferences -> Keyboard -> Input Sources" and + add "Pinyin – Traditional" or "Pinyin – Simplified" IM from Chinese language group. + Set current IM to "Pinyin". + + 1. Set focus to the text field below and press "comma" character + on the keyboard. + 2. Now change the current IM to the IM used before "Pinyin" or to "U.S". + Press comma character again. + 3. You should notice a difference in the comma. Pinyin IM should output + full width comma "\uff0c" and the other IM should output a Latin comma "\u002c". + + If above is true press "PASS", if "\u002c" character is displayed for Pinyin IM, press "FAIL". + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Comma using Pinyin Input Method") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(45) + .splitUIBottom(PinyinIMCommaTest::createUI) + .testTimeOut(10) + .build() + .awaitAndCheck(); + } + + private static JComponent createUI() { + JPanel panel = new JPanel(); + panel.add(new JLabel("Text field:")); + panel.add(new JTextField(20)); + return panel; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/PinyinIMFullstopTest.java openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMFullstopTest.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/PinyinIMFullstopTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/PinyinIMFullstopTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; + +/* + * @test + * @bug 8132503 + * @summary [macosx] Chinese full stop symbol cannot be entered with Pinyin IM on OS X + * @requires (os.family == "mac") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PinyinIMFullstopTest + */ + +public class PinyinIMFullstopTest { + private static final String INSTRUCTIONS = """ + This test verifies if Chinese full stop symbol can be entered in JTextArea + with Pinyin input method (IM). + + Test settings: + Go to "System Preferences -> Keyboard -> Input Sources" and + add "Pinyin – Traditional" or "Pinyin – Simplified" IM from Chinese language group. + Set current IM to "Pinyin". + + 1. Set focus to the text area below and press "dot" character + on the keyboard. + 2. Now change the current IM to the IM used before "Pinyin" or to "U.S". + Press dot character again. + 3. You should notice a difference in the dot. Pinyin IM should output + "。" and the other IM should output "." + + If above is true press "PASS", if normal fullstop "." character is displayed + for Pinyin IM, press "FAIL". + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Dot using Pinyin Input Method") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(45) + .splitUIBottom(PinyinIMFullstopTest::createUI) + .testTimeOut(10) + .build() + .awaitAndCheck(); + } + + private static JComponent createUI() { + JPanel panel = new JPanel(); + JTextArea textArea = new JTextArea(5, 40); + panel.add(new JLabel("Text Area:")); + panel.add(textArea); + return panel; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/im/bug4490692.java openjdk-21-21.0.9+10/test/jdk/java/awt/im/bug4490692.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/im/bug4490692.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/im/bug4490692.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2007, 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.event.KeyAdapter; +import java.awt.event.KeyEvent; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +/* + * @test + * @bug 4490692 + * @summary [Linux] Test for KEY_PRESS event for accented characters. + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4490692 + */ + +public class bug4490692 { + private static final String INSTRUCTIONS = """ + This test is for unix platforms only. + Before the test, you need to modify the keyboard mapping for + Tab by issuing the following command: + + xmodmap -e 'keycode 23 = aacute' (this is for Linux) + xmodmap -e 'keycode 60 = aacute' (this is for Solaris Sparc) + + This command lets you type 'a with acute (à)' character when you press + 'Tab' key in the JTextField provided below the logging area. + After the test, please DO NOT fail to restore the original + key mapping by doing the following. + + xmodmap -e 'keycode 23 = Tab' (this is for Linux) + xmodmap -e 'keycode 60 = Tab' (this is for Solaris Sparc) + + CASE 1: This is a manual check and for SOLARIS SPARC keyboard + only. Check whether the key sequence ("Compose", "a", " ' ") + generates a-acute character in en_US locale. + + CASE 2: This step is automated and applicable for both + keyboards - LINUX & SOLARIS SPARC. + When Tab key is pressed it should generate a-acute (à) + character, this test automatically passes if the correct character + is generated on keypress else fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(45) + .testTimeOut(10) + .splitUIBottom(bug4490692::createUI) + .logArea(8) + .build() + .awaitAndCheck(); + } + + private static JComponent createUI() { + JPanel panel = new JPanel(); + JTextField textField = new JTextField("", 20); + panel.add(new JLabel("Text field:")); + + textField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + PassFailJFrame.log(e.paramString()); + if (e.getKeyCode() == 23 || e.getKeyCode() == 60 + || e.paramString().contains("rawCode=23") + || e.paramString().contains("rawCode=60")) { + if (e.getKeyChar() == 0x00e1) { + PassFailJFrame.forcePass(); + } else { + PassFailJFrame.forceFail("Tab keypress DID NOT" + + " produce the expected accented character - aacute"); + } + } + } + }); + + panel.add(textField); + return panel; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/print/PrinterJob/PrintNullString.java openjdk-21-21.0.9+10/test/jdk/java/awt/print/PrinterJob/PrintNullString.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/print/PrinterJob/PrintNullString.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/print/PrinterJob/PrintNullString.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -21,164 +21,113 @@ * questions. */ -import java.awt.Button; -import java.awt.Dimension; -import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Panel; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; +import java.io.File; import java.text.AttributedCharacterIterator; import java.text.AttributedString; -import javax.swing.JOptionPane; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.Destination; /* * @test * @bug 4223328 - * @summary Printer graphics must behave the same as screen graphics + * @summary Printer graphics must throw expected exceptions * @key printer - * @library /java/awt/regtesthelpers - * @build PassFailJFrame - * @run main/manual PrintNullString + * @run main PrintNullString */ -public class PrintNullString extends Frame { - private static final String INSTRUCTIONS = - "This test should print a page which contains the same\n" + - "text messages as in the test window on the screen.\n" + - "\n" + - "The messages should contain only 'OK' and 'expected' messages.\n" + - "Press Pass if it's the case; otherwise press Fail.\n" + - "\n" + - "If the page fails to print, but there were no exceptions\n" + - "then the problem is likely elsewhere (i.e. your printer)"; +public class PrintNullString implements Printable { + private final String nullStr = null; + private final String emptyStr = ""; + private final AttributedString emptyAttStr = new AttributedString(emptyStr); + private final AttributedCharacterIterator nullIterator = null; + private final AttributedCharacterIterator emptyIterator = emptyAttStr.getIterator(); public static void main(String[] args) throws Exception { if (PrinterJob.lookupPrintServices().length == 0) { throw new RuntimeException("Printer not configured or available."); } - PassFailJFrame.builder() - .instructions(INSTRUCTIONS) - .testUI(PrintNullString::new) - .rows((int) INSTRUCTIONS.lines().count() + 1) - .columns(45) - .build() - .awaitAndCheck(); + new PrintNullString(); } - public PrintNullString() { - super("PrintNullString"); + public PrintNullString() throws PrinterException { + PrinterJob pj = PrinterJob.getPrinterJob(); + pj.setPrintable(this, new PageFormat()); + PrintRequestAttributeSet pSet = new HashPrintRequestAttributeSet(); + File file = new File("out.prn"); + file.deleteOnExit(); + pSet.add(new Destination(file.toURI())); + pj.print(pSet); + } + + @Override + public int print(Graphics g, PageFormat pgFmt, int pgIndex) { + if (pgIndex > 0) { + return NO_SUCH_PAGE; + } - TextCanvas c = new TextCanvas(); - add("Center", c); + Graphics2D g2d = (Graphics2D) g; + g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); - Button b = new Button("Print"); - add("South", b); - b.addActionListener(e -> { - PrinterJob pj = PrinterJob.getPrinterJob(); - if (pj.printDialog()) { - pj.setPrintable(c); - try { - pj.print(); - } catch (PrinterException ex) { - ex.printStackTrace(); - String msg = "PrinterException: " + ex.getMessage(); - JOptionPane.showMessageDialog(b, msg, "Error occurred", - JOptionPane.ERROR_MESSAGE); - PassFailJFrame.forceFail(msg); - } - } - }); - pack(); - } + // API 1: null & empty drawString(String, int, int); + try { + g2d.drawString(nullStr, 20, 40); + throw new RuntimeException("FAILURE: No NPE for null String, int"); + } catch (NullPointerException e) { + g2d.drawString("caught expected NPE for null String, int", 20, 40); + } + + g2d.drawString(emptyStr, 20, 60); + g2d.drawString("OK for empty String, int", 20, 60); + + // API 2: null & empty drawString(String, float, float); + try { + g2d.drawString(nullStr, 20.0f, 80.0f); + throw new RuntimeException("FAILURE: No NPE for null String, float"); + } catch (NullPointerException e) { + g2d.drawString("caught expected NPE for null String, float", 20, 80); + } - private static class TextCanvas extends Panel implements Printable { - private final String nullStr = null; - private final String emptyStr = ""; - private final AttributedString emptyAttStr = new AttributedString(emptyStr); - private final AttributedCharacterIterator nullIterator = null; - private final AttributedCharacterIterator emptyIterator = emptyAttStr.getIterator(); - - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - paint(g2d); - } - - @Override - public int print(Graphics g, PageFormat pgFmt, int pgIndex) { - if (pgIndex > 0) { - return NO_SUCH_PAGE; - } - - Graphics2D g2d = (Graphics2D) g; - g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); - paint(g2d); - - return PAGE_EXISTS; - } - - private void paint(Graphics2D g2d) { - // API 1: null & empty drawString(String, int, int); - try { - g2d.drawString(nullStr, 20, 40); - g2d.drawString("FAILURE: No NPE for null String, int", 20, 40); - } catch (NullPointerException e) { - g2d.drawString("caught expected NPE for null String, int", 20, 40); - } - - g2d.drawString(emptyStr, 20, 60); - g2d.drawString("OK for empty String, int", 20, 60); - - // API 2: null & empty drawString(String, float, float); - try { - g2d.drawString(nullStr, 20.0f, 80.0f); - g2d.drawString("FAILURE: No NPE for null String, float", 20, 80); - } catch (NullPointerException e) { - g2d.drawString("caught expected NPE for null String, float", 20, 80); - } - - g2d.drawString(emptyStr, 20.0f, 100.0f); - g2d.drawString("OK for empty String, float", 20.0f, 100.f); - - // API 3: null & empty drawString(Iterator, int, int); - try { - g2d.drawString(nullIterator, 20, 120); - g2d.drawString("FAILURE: No NPE for null iterator, int", 20, 120); - } catch (NullPointerException e) { - g2d.drawString("caught expected NPE for null iterator, int", 20, 120); - } - - try { - g2d.drawString(emptyIterator, 20, 140); - g2d.drawString("FAILURE: No IAE for empty iterator, int", 20, 140); - } catch (IllegalArgumentException e) { - g2d.drawString("caught expected IAE for empty iterator, int", 20, 140); - } - - // API 4: null & empty drawString(Iterator, float, int); - try { - g2d.drawString(nullIterator, 20.0f, 160.0f); - g2d.drawString("FAILURE: No NPE for null iterator, float", 20, 160); - } catch (NullPointerException e) { - g2d.drawString("caught expected NPE for null iterator, float", 20, 160); - } - - try { - g2d.drawString(emptyIterator, 20.0f, 180.0f); - g2d.drawString("FAILURE: No IAE for empty iterator, float", 20, 180); - } catch (IllegalArgumentException e) { - g2d.drawString("caught expected IAE for empty iterator, float", 20, 180); - } - } - - @Override - public Dimension getPreferredSize() { - return new Dimension(450, 250); + g2d.drawString(emptyStr, 20.0f, 100.0f); + g2d.drawString("OK for empty String, float", 20.0f, 100.f); + + // API 3: null & empty drawString(Iterator, int, int); + try { + g2d.drawString(nullIterator, 20, 120); + throw new RuntimeException("FAILURE: No NPE for null iterator, int"); + } catch (NullPointerException e) { + g2d.drawString("caught expected NPE for null iterator, int", 20, 120); + } + + try { + g2d.drawString(emptyIterator, 20, 140); + throw new RuntimeException("FAILURE: No IAE for empty iterator, int"); + } catch (IllegalArgumentException e) { + g2d.drawString("caught expected IAE for empty iterator, int", 20, 140); + } + + // API 4: null & empty drawString(Iterator, float, int); + try { + g2d.drawString(nullIterator, 20.0f, 160.0f); + throw new RuntimeException("FAILURE: No NPE for null iterator, float"); + } catch (NullPointerException e) { + g2d.drawString("caught expected NPE for null iterator, float", 20, 160); + } + + try { + g2d.drawString(emptyIterator, 20.0f, 180.0f); + throw new RuntimeException("FAILURE: No IAE for empty iterator, float"); + } catch (IllegalArgumentException e) { + g2d.drawString("caught expected IAE for empty iterator, float", 20, 180); } + + return PAGE_EXISTS; } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java openjdk-21-21.0.9+10/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java --- openjdk-21-21.0.8+9/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java 2025-10-13 07:49:24.000000000 +0000 @@ -150,6 +150,17 @@ * Before returning from {@code awaitAndCheck}, the framework disposes of * all the windows and frames. * + *

+ * For semi-automatic tests, use {@code forcePass} or + * {@code forceFail} methods to forcibly pass or fail the test + * when it's determined that the required conditions are already met + * or cannot be met correspondingly. + * These methods release {@code awaitAndCheck}, and + * the test will complete successfully or fail. + *

+ * Refer to examples of using these methods in the description of the + * {@link #forcePass() forcePass} and {@link #forceFail() forceFail} methods. + * *

Sample Manual Test

* A simple test would look like this: * {@snippet id='sampleManualTestCode' lang='java': @@ -1294,28 +1305,50 @@ /** * Forcibly pass the test. - *

The sample usage: - *


-     *      PrinterJob pj = PrinterJob.getPrinterJob();
-     *      if (pj == null || pj.getPrintService() == null) {
-     *          System.out.println(""Printer not configured or available.");
-     *          PassFailJFrame.forcePass();
-     *      }
-     * 
+ *

+ * Use this method in semi-automatic tests when + * the test determines that all the conditions for passing the test are met. + *

+ * Do not use this method in cases where a resource is unavailable or a + * feature isn't supported, throw {@code jtreg.SkippedException} instead. + * + *

A sample usage can be found in + * {@code + * SaveFileNameOverrideTest.java} */ public static void forcePass() { latch.countDown(); } /** - * Forcibly fail the test. + * Forcibly fail the test. + *

+ * Use this method in semi-automatic tests when + * it is determined that the conditions for passing the test cannot be met. + *

+ * Do not use this method in cases where a resource is unavailable or a + * feature isn't supported, throw {@code jtreg.SkippedException} instead. + * + *

A sample usage can be found in + * {@code + * HorizScrollers.java} */ public static void forceFail() { forceFail("forceFail called"); } /** - * Forcibly fail the test and provide a reason. + * Forcibly fail the test and provide a reason. + *

+ * Use this method in semi-automatic tests when + * it is determined that the conditions for passing the test cannot be met. + *

+ * Do not use this method in cases where a resource is unavailable or a + * feature isn't supported, throw {@code jtreg.SkippedException} instead. + * + *

A sample usage can be found in + * {@code + * SaveFileNameOverrideTest.java} * * @param reason the reason why the test is failed */ @@ -1714,7 +1747,7 @@ * * @throws IllegalStateException if a {@code PanelCreator} is * already set - * @throws IllegalArgumentException if {panelCreator} is {@code null} + * @throws IllegalArgumentException if {@code panelCreator} is {@code null} */ public Builder splitUI(PanelCreator panelCreator) { return splitUIRight(panelCreator); @@ -1731,7 +1764,7 @@ * * @throws IllegalStateException if a {@code PanelCreator} is * already set - * @throws IllegalArgumentException if {panelCreator} is {@code null} + * @throws IllegalArgumentException if {@code panelCreator} is {@code null} */ public Builder splitUIRight(PanelCreator panelCreator) { return splitUI(panelCreator, JSplitPane.HORIZONTAL_SPLIT); @@ -1748,7 +1781,7 @@ * * @throws IllegalStateException if a {@code PanelCreator} is * already set - * @throws IllegalArgumentException if {panelCreator} is {@code null} + * @throws IllegalArgumentException if {@code panelCreator} is {@code null} */ public Builder splitUIBottom(PanelCreator panelCreator) { return splitUI(panelCreator, JSplitPane.VERTICAL_SPLIT); @@ -1764,7 +1797,7 @@ * * @throws IllegalStateException if a {@code PanelCreator} is * already set - * @throws IllegalArgumentException if {panelCreator} is {@code null} + * @throws IllegalArgumentException if {@code panelCreator} is {@code null} */ private Builder splitUI(PanelCreator panelCreator, int splitUIOrientation) { diff -Nru openjdk-21-21.0.8+9/test/jdk/java/beans/Introspector/DefaultMethodBeanPropertyTest.java openjdk-21-21.0.9+10/test/jdk/java/beans/Introspector/DefaultMethodBeanPropertyTest.java --- openjdk-21-21.0.8+9/test/jdk/java/beans/Introspector/DefaultMethodBeanPropertyTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/beans/Introspector/DefaultMethodBeanPropertyTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -23,20 +23,26 @@ /* * @test - * @bug 8071693 + * @bug 8071693 8347826 * @summary Verify that the Introspector finds default methods inherited * from interfaces */ +import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; +import java.beans.MethodDescriptor; import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.NavigableSet; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; public class DefaultMethodBeanPropertyTest { @@ -78,11 +84,17 @@ } public static void testScenario1() { + verifyMethods(D1.class, + "public static int DefaultMethodBeanPropertyTest$A1.getStaticValue()", + "public default int DefaultMethodBeanPropertyTest$A1.getValue()", + "public java.lang.Integer DefaultMethodBeanPropertyTest$D1.getFoo()", + "public java.lang.Float DefaultMethodBeanPropertyTest$D1.getObj()" + ); verifyProperties(D1.class, - "getClass", // inherited method - "getValue", // inherited default method - "getFoo", // overridden interface method - "getObj" // overridden default method + "public final native java.lang.Class java.lang.Object.getClass()", + "public default int DefaultMethodBeanPropertyTest$A1.getValue()", + "public java.lang.Integer DefaultMethodBeanPropertyTest$D1.getFoo()", + "public java.lang.Float DefaultMethodBeanPropertyTest$D1.getObj()" ); } @@ -108,9 +120,12 @@ } public static void testScenario2() { + verifyMethods(D2.class, + "public default java.lang.Object DefaultMethodBeanPropertyTest$A2.getFoo()" + ); verifyProperties(D2.class, - "getClass", - "getFoo" + "public final native java.lang.Class java.lang.Object.getClass()", + "public default java.lang.Object DefaultMethodBeanPropertyTest$A2.getFoo()" ); } @@ -144,60 +159,404 @@ } public static void testScenario3() { + verifyMethods(D3.class, + "public java.util.NavigableSet DefaultMethodBeanPropertyTest$D3.getFoo()" + ); verifyProperties(D3.class, - "getClass", - "getFoo" + "public final native java.lang.Class java.lang.Object.getClass()", + "public java.util.NavigableSet DefaultMethodBeanPropertyTest$D3.getFoo()" ); } -// Helper methods +////////////////////////////////////// +// // +// SCENARIO 4 // +// // +////////////////////////////////////// - public static void verifyProperties(Class type, String... getterNames) { + public interface A4 { + default Object getDefault0() { + return null; + } + default Object getDefault1() { + return null; + } + default Object getDefault2() { + return null; + } + default Object getDefault3() { + return null; + } + Object getNonDefault(); + } - // Gather expected properties - final HashSet expected = new HashSet<>(); - for (String methodName : getterNames) { - final String suffix = methodName.substring(3); - final String propName = Introspector.decapitalize(suffix); - final Method getter; + public class B4 implements A4 { + @Override + public Object getDefault1() { + return new B4(); + } + @Override + public String getDefault2() { + return null; + } + @Override + public Float getDefault3() { + return null; + } + public Long getNonDefault() { + return null; + } + } + + public static void testScenario4() { + verifyMethods(B4.class, + "public default java.lang.Object DefaultMethodBeanPropertyTest$A4.getDefault0()", + "public java.lang.Object DefaultMethodBeanPropertyTest$B4.getDefault1()", + "public java.lang.String DefaultMethodBeanPropertyTest$B4.getDefault2()", + "public java.lang.Float DefaultMethodBeanPropertyTest$B4.getDefault3()", + "public java.lang.Long DefaultMethodBeanPropertyTest$B4.getNonDefault()" + ); + verifyProperties(B4.class, + "public final native java.lang.Class java.lang.Object.getClass()", + "public default java.lang.Object DefaultMethodBeanPropertyTest$A4.getDefault0()", + "public java.lang.Object DefaultMethodBeanPropertyTest$B4.getDefault1()", + "public java.lang.String DefaultMethodBeanPropertyTest$B4.getDefault2()", + "public java.lang.Float DefaultMethodBeanPropertyTest$B4.getDefault3()", + "public java.lang.Long DefaultMethodBeanPropertyTest$B4.getNonDefault()" + ); + } + +////////////////////////////////////// +// // +// SCENARIO 5 // +// // +////////////////////////////////////// + + public interface A5 { + public default void setParentFoo(Integer num) { + } + public default void setFoo(String num) { + } + public static int getStaticValue() { + return 0; + } + private int getPrivateValue() { + return 0; + } + } + + public class B5 implements A5 { + public void setFoo(Number num) { + } + public void setLocalFoo(Long num) { + } + public static int getStaticValue() { + return 0; + } + } + + public static void testScenario5() { + verifyMethods(B5.class, + "public static int DefaultMethodBeanPropertyTest$B5.getStaticValue()", + "public default void DefaultMethodBeanPropertyTest$A5.setFoo(java.lang.String)", + "public default void DefaultMethodBeanPropertyTest$A5.setParentFoo(java.lang.Integer)", + "public void DefaultMethodBeanPropertyTest$B5.setFoo(java.lang.Number)", + "public void DefaultMethodBeanPropertyTest$B5.setLocalFoo(java.lang.Long)" + ); + verifyProperties(B5.class, + "public final native java.lang.Class java.lang.Object.getClass()", + "public default void DefaultMethodBeanPropertyTest$A5.setParentFoo(java.lang.Integer)", + "public void DefaultMethodBeanPropertyTest$B5.setFoo(java.lang.Number)", + "public void DefaultMethodBeanPropertyTest$B5.setLocalFoo(java.lang.Long)" + ); + } + +////////////////////////////////////// +// // +// SCENARIO 6 // +// // +////////////////////////////////////// + + public class A6 { + public void setParentFoo(Integer num) { + } + public void setFoo(Integer num) { + } + public static int getStaticValue() { + return 0; + } + private int getPrivateValue() { + return 0; + } + } + + public class B6 extends A6 { + public void setFoo(String num) { + } + public void setLocalFoo(Long num) { + } + public static int getStaticValue() { + return 0; + } + } + + public static void testScenario6() { + verifyMethods(B6.class, + "public static int DefaultMethodBeanPropertyTest$B6.getStaticValue()", + "public void DefaultMethodBeanPropertyTest$A6.setFoo(java.lang.Integer)", + "public void DefaultMethodBeanPropertyTest$A6.setParentFoo(java.lang.Integer)", + "public void DefaultMethodBeanPropertyTest$B6.setFoo(java.lang.String)", + "public void DefaultMethodBeanPropertyTest$B6.setLocalFoo(java.lang.Long)" + ); + verifyProperties(B6.class, + "public final native java.lang.Class java.lang.Object.getClass()", + "public void DefaultMethodBeanPropertyTest$A6.setParentFoo(java.lang.Integer)", + "public void DefaultMethodBeanPropertyTest$B6.setFoo(java.lang.String)", + "public void DefaultMethodBeanPropertyTest$B6.setLocalFoo(java.lang.Long)" + ); + } + +////////////////////////////////////// +// // +// SCENARIO 7 // +// // +////////////////////////////////////// + + interface A7 { + T getValue(); + } + + interface B7 { + Runnable getValue(); + } + + interface AB7 extends B7, A7 { + Runnable getValue(); + } + + abstract class D7 implements AB7 { + public void setValue(Runnable value) { + } + } + + public static void testScenario7() { + verifyMethods(D7.class, + "public void DefaultMethodBeanPropertyTest$D7.setValue(java.lang.Runnable)" + ); + verifyProperties(D7.class, + "public final native java.lang.Class java.lang.Object.getClass()", + "public void DefaultMethodBeanPropertyTest$D7.setValue(java.lang.Runnable)" + ); + } + +////////////////////////////////////// +// // +// SCENARIO 8 // +// // +////////////////////////////////////// + + public interface A8 { + public default void setFoo(Float num) { + } + public default void setFoo2(Integer num) { + } + } + public interface B8 extends A8 { + public default void setFoo(Integer num) { + } + public default void setFoo2(Float num) { + } + } + + public class C8 implements B8 { + } + + public static void testScenario8() { + verifyMethods(C8.class, + "public default void DefaultMethodBeanPropertyTest$A8.setFoo(java.lang.Float)", + "public default void DefaultMethodBeanPropertyTest$A8.setFoo2(java.lang.Integer)", + "public default void DefaultMethodBeanPropertyTest$B8.setFoo(java.lang.Integer)", + "public default void DefaultMethodBeanPropertyTest$B8.setFoo2(java.lang.Float)" + ); + verifyProperties(C8.class, + "public final native java.lang.Class java.lang.Object.getClass()", + "public default void DefaultMethodBeanPropertyTest$B8.setFoo(java.lang.Integer)", + "public default void DefaultMethodBeanPropertyTest$B8.setFoo2(java.lang.Float)" + ); + } + +////////////////////////////////////// +// // +// SCENARIO 9 // +// // +////////////////////////////////////// + + public class A9 { + public void setFoo(Object value) { + } + public void setFoo(String value) { + } + public void setFoo2(Object value) { + } + public void setFoo2(Integer value) { + } + // For the same setters with inconvertible arg types PropertyInfo behavior is undefined. + // public void setLocalFoo3(Long num) { } + // public void setLocalFoo3(Float num) { } + } + + public static void testScenario9() { + verifyMethods(A9.class, + "public void DefaultMethodBeanPropertyTest$A9.setFoo(java.lang.String)", + "public void DefaultMethodBeanPropertyTest$A9.setFoo(java.lang.Object)", + "public void DefaultMethodBeanPropertyTest$A9.setFoo2(java.lang.Integer)", + "public void DefaultMethodBeanPropertyTest$A9.setFoo2(java.lang.Object)" + ); + verifyProperties(A9.class, + "public final native java.lang.Class java.lang.Object.getClass()", + "public void DefaultMethodBeanPropertyTest$A9.setFoo(java.lang.String)", + "public void DefaultMethodBeanPropertyTest$A9.setFoo2(java.lang.Integer)" + ); + } + +////////////////////////////////////// +// // +// SCENARIO 10 // +// // +////////////////////////////////////// + + public static class A10 { + public Object getProp() { + return null; + } + } + + public static interface B10 { + Object getProp(); + } + + public static class C10_1 extends A10 implements B10 { + } + + public static class C10_2 extends A10 implements B10 { + } + + public static class A10BeanInfo extends SimpleBeanInfo { + public MethodDescriptor[] getMethodDescriptors() { try { - getter = type.getMethod(methodName); - } catch (NoSuchMethodException e) { - throw new Error("unexpected error", e); + Class params[] = {}; + MethodDescriptor md = new MethodDescriptor(A10.class.getDeclaredMethod("getProp", params)); + md.setDisplayName("display name"); + MethodDescriptor res[] = { md }; + return res; + } catch (Exception exception) { + throw new Error("unexpected exception", exception); } - final PropertyDescriptor propDesc; + } + } + + public static class C10_1BeanInfo extends SimpleBeanInfo { + public BeanInfo[] getAdditionalBeanInfo() { + try { + BeanInfo res[] = { + Introspector.getBeanInfo(A10.class), + Introspector.getBeanInfo(B10.class) + }; + return res; + } catch (IntrospectionException exception) { + throw new Error("unexpected exception", exception); + } + } + } + + public static class C10_2BeanInfo extends SimpleBeanInfo { + public BeanInfo[] getAdditionalBeanInfo() { try { - propDesc = new PropertyDescriptor(propName, getter, null); - } catch (IntrospectionException e) { - throw new Error("unexpected error", e); + BeanInfo res[] = { + Introspector.getBeanInfo(B10.class), + Introspector.getBeanInfo(A10.class) + }; + return res; + } catch (IntrospectionException exception) { + throw new Error("unexpected exception", exception); } - expected.add(propDesc); } + } - // Verify properties can be found directly - expected.stream() - .map(PropertyDescriptor::getName) - .filter(name -> BeanUtils.getPropertyDescriptor(type, name) == null) - .findFirst() - .ifPresent(name -> { - throw new Error("property \"" + name + "\" not found in " + type); - }); - - // Gather actual properties - final Set actual = - Set.of(BeanUtils.getPropertyDescriptors(type)); + public static void testScenario10() { + { + var md = getMethodDescriptor(C10_1.class, A10.class, "getProp"); + assertEquals("display name", md.getDisplayName(), "getDisplayName()"); + } + { + var md = getMethodDescriptor(C10_2.class, A10.class, "getProp"); + assertEquals("display name", md.getDisplayName(), "getDisplayName()"); + } + } - // Verify the two sets are the same +// Helper methods + + private static void verifyEquality(String title, Set expected, Set actual) { if (!actual.equals(expected)) { - throw new Error("mismatch: " + type - + "\nACTUAL:\n " - + actual.stream() - .map(Object::toString) - .collect(Collectors.joining("\n ")) - + "\nEXPECTED:\n " - + expected.stream() - .map(Object::toString) - .collect(Collectors.joining("\n "))); + throw new Error(title + " mismatch: " + + "\nACTUAL:\n " + + actual.stream() + .map(Object::toString) + .collect(Collectors.joining("\n ")) + + "\nEXPECTED:\n " + + expected.stream() + .map(Object::toString) + .collect(Collectors.joining("\n "))); + } + } + + public static void verifyProperties(Class type, String... methodNames) { + try { + final Set expected = new HashSet<>(Arrays.asList(methodNames)); + final Set actual = Arrays + .stream(Introspector.getBeanInfo(type) + .getPropertyDescriptors()) + .flatMap(pd -> Stream.of(pd.getReadMethod(), pd.getWriteMethod())) + .filter(Objects::nonNull) + .map((Method m) -> m.toString()) + .collect(Collectors.toSet()); + verifyEquality("properties", expected, actual); + } catch (IntrospectionException exception) { + throw new Error("unexpected exception", exception); + } + } + + public static void verifyMethods(Class type, String... methodNames) { + try { + final Set expected = new HashSet<>(Arrays.asList(methodNames)); + final Set actual = Arrays + .stream(Introspector.getBeanInfo(type, Object.class) + .getMethodDescriptors()) + .map(MethodDescriptor::getMethod) + .map(Method::toString) + .collect(Collectors.toSet()); + verifyEquality("methods", expected, actual); + } catch (IntrospectionException exception) { + throw new Error("unexpected exception", exception); + } + } + + private static MethodDescriptor getMethodDescriptor(Class cls, Class stop, String name) { + try { + for (var md : Introspector.getBeanInfo(cls, stop).getMethodDescriptors()) { + if (md.getName().equals(name)) { + return md; + } + } + return null; + } catch (IntrospectionException exception) { + throw new Error("unexpected exception", exception); + } + } + + private static void assertEquals(Object expected, Object actual, String msg) { + if (!expected.equals(actual)) { + throw new Error(msg + ":\nACTUAL: " + actual + "\nEXPECTED: " + expected); } } @@ -207,5 +566,12 @@ testScenario1(); testScenario2(); testScenario3(); + testScenario4(); + testScenario5(); + testScenario6(); + testScenario7(); + testScenario8(); + testScenario9(); + testScenario10(); } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/lang/Class/ProtectionDomainRace.java openjdk-21-21.0.9+10/test/jdk/java/lang/Class/ProtectionDomainRace.java --- openjdk-21-21.0.8+9/test/jdk/java/lang/Class/ProtectionDomainRace.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/lang/Class/ProtectionDomainRace.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * 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 8334394 + * @summary ensure there is no race condition in Class::protectionDomain + * @run main/othervm ProtectionDomainRace + */ +import javax.security.auth.Subject; +import java.security.PrivilegedAction; + +/** + * Without the code fix, this test would fail with + * java.lang.AssertionError: sun.security.util.ResourcesMgr (PD) + * at java.base/java.lang.invoke.MethodHandleImpl$BindCaller.checkInjectedInvoker(MethodHandleImpl.java:1209) + * at java.base/java.lang.invoke.MethodHandleImpl$BindCaller.makeInjectedInvoker(MethodHandleImpl.java:1110) + * at java.base/java.lang.invoke.MethodHandleImpl$BindCaller$1.computeValue(MethodHandleImpl.java:1117) + * at java.base/java.lang.invoke.MethodHandleImpl$BindCaller$1.computeValue(MethodHandleImpl.java:1114) + * at java.base/java.lang.ClassValue.getFromHashMap(ClassValue.java:229) + * at java.base/java.lang.ClassValue.getFromBackup(ClassValue.java:211) + * at java.base/java.lang.ClassValue.get(ClassValue.java:117) + * at java.base/java.lang.invoke.MethodHandleImpl$BindCaller.bindCallerWithInjectedInvoker(MethodHandleImpl.java:1089) + * at java.base/java.lang.invoke.MethodHandleImpl$BindCaller.bindCaller(MethodHandleImpl.java:1077) + * at java.base/java.lang.invoke.MethodHandleImpl.bindCaller(MethodHandleImpl.java:1032) + * at java.base/java.lang.invoke.MethodHandles$Lookup.maybeBindCaller(MethodHandles.java:4149) + * at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:4133) + * at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(MethodHandles.java:4077) + * at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectMethodForConstant(MethodHandles.java:4326) + * at java.base/java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:4274) + * at java.base/java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:628) + * at java.base/sun.security.util.ResourcesMgr.getBundle(ResourcesMgr.java:54) + * at java.base/sun.security.util.ResourcesMgr.getString(ResourcesMgr.java:40) + * at java.base/javax.security.auth.Subject.doAs(Subject.java:517) + * ... + * as the Class::protectionDomain might assign different objects to the (original) allPermDomain field. + */ +public class ProtectionDomainRace { + private static volatile Throwable failed = null; + public static void main(String[] args) throws Throwable { + PrivilegedAction pa = () -> null; + Thread[] threads = new Thread[100]; + for (int i = 0; i < 100; i++) { + threads[i] = new Thread(() -> { + try { + Subject.doAs(null, pa); + } catch (Throwable t) { + failed = t; + } + }); + threads[i].start(); + } + for (int i = 0; i < 100; i++) { + threads[i].join(); + } + if (failed != null) { + throw failed; + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/lang/ProcessBuilder/Basic.java openjdk-21-21.0.9+10/test/jdk/java/lang/ProcessBuilder/Basic.java --- openjdk-21-21.0.8+9/test/jdk/java/lang/ProcessBuilder/Basic.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/lang/ProcessBuilder/Basic.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -36,8 +36,8 @@ * @requires !vm.musl * @requires vm.flagless * @library /test/lib - * @run main/othervm/native/timeout=300 -Djava.security.manager=allow Basic - * @run main/othervm/native/timeout=300 -Djava.security.manager=allow -Djdk.lang.Process.launchMechanism=fork Basic + * @run main/othervm/native/timeout=360 -Djava.security.manager=allow Basic + * @run main/othervm/native/timeout=360 -Djava.security.manager=allow -Djdk.lang.Process.launchMechanism=fork Basic * @author Martin Buchholz */ @@ -209,7 +209,7 @@ private static final Runtime runtime = Runtime.getRuntime(); - private static final String[] winEnvCommand = {"cmd.exe", "/c", "set"}; + private static final String[] winEnvCommand = {"cmd.exe", "/d", "/c", "set"}; private static String winEnvFilter(String env) { return env.replaceAll("\r", "") @@ -1914,7 +1914,9 @@ // Test Runtime.exec(...envp...) with envstrings without any `=' //---------------------------------------------------------------- try { - String[] cmdp = {"echo"}; + // In Windows CMD (`cmd.exe`), `echo/` outputs a newline (i.e., an empty line). + // Wrapping it with `cmd.exe /c` ensures compatibility in both native Windows and Cygwin environments. + String[] cmdp = Windows.is() ? new String[]{"cmd.exe", "/c", "echo/"} : new String[]{"echo"}; String[] envp = {"Hello", "World"}; // Yuck! Process p = Runtime.getRuntime().exec(cmdp, envp); equal(commandOutput(p), "\n"); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/lang/management/ThreadMXBean/Locks.java openjdk-21-21.0.9+10/test/jdk/java/lang/management/ThreadMXBean/Locks.java --- openjdk-21-21.0.8+9/test/jdk/java/lang/management/ThreadMXBean/Locks.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/lang/management/ThreadMXBean/Locks.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -422,6 +422,9 @@ lock + " expected to have owner"); } for (ThreadInfo info1 : infos) { + if (info1 == null) { + continue; // Missing thread, e.g. completed. Ignore. + } if (info1.getThreadId() == threadId) { ownerInfo = info1; break; diff -Nru openjdk-21-21.0.8+9/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java openjdk-21-21.0.9+10/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java --- openjdk-21-21.0.8+9/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -47,6 +47,7 @@ import java.lang.management.ThreadMXBean; import java.util.Arrays; import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; import jdk.test.lib.thread.VThreadRunner; @@ -55,6 +56,8 @@ private static final Object LOCK2 = new Object(); private static final CyclicBarrier barrier = new CyclicBarrier(2); + private static final AtomicBoolean reached1 = new AtomicBoolean(); + private static final AtomicBoolean reached2 = new AtomicBoolean(); /** * PP = test deadlock with two platform threads @@ -72,6 +75,7 @@ Thread thread1 = builder1.start(() -> { synchronized (LOCK1) { try { barrier.await(); } catch (Exception ie) {} + reached1.set(true); synchronized (LOCK2) { } } }); @@ -84,14 +88,15 @@ Thread thread2 = builder2.start(() -> { synchronized (LOCK2) { try { barrier.await(); } catch (Exception ie) {} + reached2.set(true); synchronized (LOCK1) { } } }); System.out.println("thread2 => " + thread2); System.out.println("Waiting for thread1 and thread2 to deadlock ..."); - awaitBlocked(thread1); - awaitBlocked(thread2); + awaitTrueAndBlocked(thread1, reached1); + awaitTrueAndBlocked(thread2, reached2); ThreadMXBean bean = ManagementFactory.getPlatformMXBean(ThreadMXBean.class); long[] deadlockedThreads = sorted(bean.findMonitorDeadlockedThreads()); @@ -108,8 +113,8 @@ throw new RuntimeException("Unexpected result"); } - private static void awaitBlocked(Thread thread) throws InterruptedException { - while (thread.getState() != Thread.State.BLOCKED) { + private static void awaitTrueAndBlocked(Thread thread, AtomicBoolean flag) throws InterruptedException { + while (!flag.get() || thread.getState() != Thread.State.BLOCKED) { Thread.sleep(10); if (!thread.isAlive()) { throw new RuntimeException("Thread " + thread + " is terminated."); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/math/BigInteger/ByteArrayConstructorTest.java openjdk-21-21.0.9+10/test/jdk/java/math/BigInteger/ByteArrayConstructorTest.java --- openjdk-21-21.0.8+9/test/jdk/java/math/BigInteger/ByteArrayConstructorTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/math/BigInteger/ByteArrayConstructorTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2023, 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 jdk.test.lib.RandomFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.math.Accessor; +import java.math.BigInteger; +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @test + * @bug 8319174 + * @summary Exercises minimality of BigInteger.mag field (use -Dseed=X to set PRANDOM seed) + * @library /test/lib + * @build jdk.test.lib.RandomFactory + * @build java.base/java.math.Accessor + * @key randomness + * @run junit/othervm -DmaxDurationMillis=3000 ByteArrayConstructorTest + */ +public class ByteArrayConstructorTest { + + private static final int DEFAULT_MAX_DURATION_MILLIS = 3_000; + + public static final int N = 1_024; + + private static int maxDurationMillis; + private static final Random rnd = RandomFactory.getRandom(); + private volatile boolean stop = false; + + @BeforeAll + static void setMaxDurationMillis() { + maxDurationMillis = Math.max(maxDurationMillis(), 0); + } + + @Test + public void testNonNegative() throws InterruptedException { + byte[] ba = nonNegativeBytes(); + doBigIntegers(ba, ba[0]); // a mask to flip to 0 and back to ba[0] + } + + @Test + public void testNegative() throws InterruptedException { + byte[] ba = negativeBytes(); + doBigIntegers(ba, (byte) ~ba[0]); // a mask to flip to -1 and back to ba[0] + } + + /* + * Starts a thread th that keeps flipping the "sign" byte in the array ba + * from the original value to 0 or -1 and back, depending on ba[0] being + * non-negative or negative, resp. + * (ba is "big endian", the least significant byte is the one with the + * highest index.) + * + * In the meantime, the current thread keeps creating BigInteger instances + * with ba and checks that the internal invariant holds, despite the + * attempts by thread th to racily modify ba. + * It does so at least as indicated by maxDurationMillis. + * + * Finally, this thread requests th to stop and joins with it, either + * because maxDurationMillis has expired, or because of an invalid invariant. + */ + private void doBigIntegers(byte[] ba, byte mask) throws InterruptedException { + Thread th = new Thread(() -> { + while (!stop) { + ba[0] ^= mask; + } + }); + th.start(); + + try { + createBigIntegers(maxDurationMillis, ba); + } finally { + stop = true; + th.join(1_000); + } + } + + private void createBigIntegers(int maxDurationMillis, byte[] ba) { + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < maxDurationMillis) { + BigInteger bi = new BigInteger(ba); + int[] mag = Accessor.mag(bi); + assertTrue(mag.length == 0 || mag[0] != 0, + String.format("inconsistent BigInteger: mag.length=%d, mag[0]=%d", + mag.length, mag[0])); + } + } + + private byte[] nonNegativeBytes() { + byte[] ba = new byte[1 + N]; + byte b0; + while ((b0 = (byte) rnd.nextInt()) < 0); // empty body + rnd.nextBytes(ba); + ba[0] = b0; + /* Except for ba[0], fill most significant half with zeros. */ + for (int i = 1; i <= N / 2; ++i) { + ba[i] = 0; + } + return ba; + } + + private byte[] negativeBytes() { + byte[] ba = new byte[1 + N]; + byte b0; + while ((b0 = (byte) rnd.nextInt()) >= 0); // empty body + rnd.nextBytes(ba); + ba[0] = b0; + /* Except for ba[0], fill most significant half with -1 bytes. */ + for (int i = 1; i <= N / 2; ++i) { + ba[i] = -1; + } + return ba; + } + + private static int maxDurationMillis() { + try { + return Integer.parseInt(System.getProperty("maxDurationMillis", + Integer.toString(DEFAULT_MAX_DURATION_MILLIS))); + } catch (NumberFormatException ignore) { + } + return DEFAULT_MAX_DURATION_MILLIS; + } + +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/math/BigInteger/java.base/java/math/Accessor.java openjdk-21-21.0.9+10/test/jdk/java/math/BigInteger/java.base/java/math/Accessor.java --- openjdk-21-21.0.8+9/test/jdk/java/math/BigInteger/java.base/java/math/Accessor.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/math/BigInteger/java.base/java/math/Accessor.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 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 java.math; + +public class Accessor { + + public static int[] mag(BigInteger bi) { + return bi.mag; + } + +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/CookieHandler/B6644726.java openjdk-21-21.0.9+10/test/jdk/java/net/CookieHandler/B6644726.java --- openjdk-21-21.0.8+9/test/jdk/java/net/CookieHandler/B6644726.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/CookieHandler/B6644726.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, 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 @@ -46,8 +46,8 @@ // Let's test the default path lst.add("myCookie1=foo"); // Then some alternate expires format - lst.add("myCookie2=bar; path=/dir; expires=Tue, 19 Aug 2025 16:00:00 GMT"); - lst.add("myCookie3=test; path=/dir; expires=Tue Aug 19 2025 16:00:00 GMT-0100"); + lst.add("myCookie2=bar; path=/dir; expires=Fri, 19 Aug 4242 16:00:00 GMT"); + lst.add("myCookie3=test; path=/dir; expires=Fri Aug 19 4242 16:00:00 GMT-0100"); // Then Netscape draft cookies and domains lst.add("myCookie4=test; domain=.sun.com; path=/dir/foo"); HashMap> map = new HashMap>(); @@ -64,7 +64,8 @@ List cookies = cs.getCookies(); // There should be 5 cookies if all dates parsed correctly if (cookies.size() != 5) { - fail("Should have 5 cookies. Got only "+ cookies.size() + ", expires probably didn't parse correctly"); + fail("unexpected cookies: " + cookies + ", should have 5 cookies. Got only " + + cookies.size() + ", expires probably didn't parse correctly"); } // Check Path for first Cookie for (HttpCookie c : cookies) { diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpect100Test.java openjdk-21-21.0.9+10/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpect100Test.java --- openjdk-21-21.0.8+9/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpect100Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpect100Test.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2023, 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 8314978 + * @summary Multiple server call from connection failing with expect100 in + * getOutputStream + * @library /test/lib + * @run junit/othervm HttpURLConnectionExpect100Test + */ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.net.HttpURLConnection; + +import jdk.test.lib.net.URIBuilder; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class HttpURLConnectionExpect100Test { + + private HttpServer server; + private int port; + static final String RESPONSE = "This is default response."; + + @BeforeAll + void setup() throws Exception { + server = HttpServer.create(); + port = server.getPort(); + } + + @AfterAll + void teardown() throws Exception { + server.close(); + } + + @Test + public void expect100ContinueHitCountTest() throws Exception { + server.resetHitCount(); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(port) + .toURL(); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("PUT"); + //send expect continue + conn.setRequestProperty("Expect", "100-continue"); + sendRequest(conn); + getHeaderField(conn); + assertEquals(1, server.getServerHitCount()); + // Server rejects the expect 100-continue request with 417 response + assertEquals(417, conn.getResponseCode()); + } + + @Test + public void defaultRequestHitCountTest() throws Exception { + server.resetHitCount(); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(port) + .toURL(); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("PUT"); + sendRequest(conn); + getHeaderField(conn); + assertEquals(1, server.getServerHitCount()); + assertEquals(200, conn.getResponseCode()); + try ( InputStream in = conn.getInputStream()) { + byte[] data = in.readAllBytes(); + assertEquals(RESPONSE.length(), data.length); + } + } + + private void sendRequest(final HttpURLConnection conn) throws Exception { + conn.setDoOutput(true); + conn.setFixedLengthStreamingMode(10); + byte[] payload = new byte[10]; + try ( OutputStream os = conn.getOutputStream()) { + os.write(payload); + os.flush(); + } catch (IOException e) { + // intentional, server will reject the expect 100 + } + } + + private void getHeaderField(final HttpURLConnection conn) { + // Call getHeaderFiels in loop, this should not hit server. + for (int i = 0; i < 5; i++) { + System.out.println("Getting: field" + i); + conn.getHeaderField("field" + i); + } + } + + static class HttpServer extends Thread { + + private final ServerSocket ss; + private static HttpServer inst; + private volatile int hitCount; + private volatile boolean isRunning; + private final int port; + + private HttpServer() throws IOException { + InetAddress loopback = InetAddress.getLoopbackAddress(); + ss = new ServerSocket(); + ss.bind(new InetSocketAddress(loopback, 0)); + port = ss.getLocalPort(); + isRunning = true; + } + + static HttpServer create() throws IOException { + if (inst != null) { + return inst; + } else { + inst = new HttpServer(); + inst.setDaemon(true); + inst.start(); + return inst; + } + } + + int getServerHitCount() { + return hitCount; + } + + void resetHitCount() { + hitCount = 0; + } + + int getPort() { + return port; + } + + void close() { + isRunning = false; + if (ss != null && !ss.isClosed()) { + try { + ss.close(); + } catch (IOException ex) { + } + } + } + + @Override + public void run() { + Socket client; + try { + while (isRunning) { + client = ss.accept(); + System.out.println(client.getRemoteSocketAddress().toString()); + hitCount++; + handleConnection(client); + } + } catch (IOException ex) { + // throw exception only if isRunning is true + if (isRunning) { + throw new RuntimeException(ex); + } + } finally { + if (ss != null && !ss.isClosed()) { + try { + ss.close(); + } catch (IOException ex) { + //ignore + } + } + } + } + + private void handleConnection(Socket client) throws IOException { + try ( BufferedReader in = new BufferedReader( + new InputStreamReader(client.getInputStream())); + PrintStream out = new PrintStream(client.getOutputStream())) { + handle_connection(in, out); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + try { + client.close(); + } catch (IOException e) { + } + } + } + + private void handle_connection(BufferedReader in, PrintStream out) + throws IOException, InterruptedException { + StringBuilder clientRequest = new StringBuilder(); + String line = null; + do { + line = in.readLine(); + clientRequest.append(line); + } while (line != null && line.length() != 0); + if (clientRequest.toString().contains("100-continue")) { + rejectExpect100Continue(out); + } else { + defaultResponse(out); + } + } + + private void rejectExpect100Continue(PrintStream out) { + out.print("HTTP/1.1 417 Expectation Failed\r\n"); + out.print("Server: Test-Server\r\n"); + out.print("Connection: close\r\n"); + out.print("Content-Length: 0\r\n"); + out.print("\r\n"); + out.flush(); + } + + private void defaultResponse(PrintStream out) { + // send the 200 OK + out.print("HTTP/1.1 200 OK\r\n"); + out.print("Server: Test-Server\r\n"); + out.print("Connection: close\r\n"); + out.print("Content-Length: " + RESPONSE.length() + "\r\n\r\n"); + out.print(RESPONSE); + out.flush(); + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java openjdk-21-21.0.9+10/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java --- openjdk-21-21.0.8+9/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -429,7 +429,7 @@ .port(control.serverSocket.getLocalPort()) .toURL(); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); connection.setDoOutput(true); connection.setReadTimeout(5000); connection.setUseCaches(false); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/Inet4Address/PingThis.java openjdk-21-21.0.9+10/test/jdk/java/net/Inet4Address/PingThis.java --- openjdk-21-21.0.8+9/test/jdk/java/net/Inet4Address/PingThis.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/Inet4Address/PingThis.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -27,27 +27,20 @@ /* @test * @bug 7163874 8133015 + * @summary InetAddress.isReachable is returning false for InetAdress 0.0.0.0 and ::0 + * @requires os.family != "windows" * @library /test/lib - * @summary InetAddress.isReachable is returning false - * for InetAdress 0.0.0.0 and ::0 * @run main PingThis * @run main/othervm -Djava.net.preferIPv4Stack=true PingThis */ -import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; import java.util.List; import jdk.test.lib.net.IPSupport; public class PingThis { public static void main(String args[]) throws Exception { - if (System.getProperty("os.name").startsWith("Windows")) { - return; - } IPSupport.throwSkippedExceptionIfNonOperational(); List addrs = new ArrayList(); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/MulticastSocket/NoLoopbackPackets.java openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/NoLoopbackPackets.java --- openjdk-21-21.0.8+9/test/jdk/java/net/MulticastSocket/NoLoopbackPackets.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/NoLoopbackPackets.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -24,8 +24,9 @@ /* * @test * @bug 4742177 - * @library /test/lib * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code + * @requires os.family != "windows" + * @library /test/lib */ import java.util.*; import java.net.*; @@ -33,20 +34,10 @@ import jdk.test.lib.net.IPSupport; public class NoLoopbackPackets { - private static String osname; - - static boolean isWindows() { - if (osname == null) - osname = System.getProperty("os.name"); - return osname.contains("Windows"); - } private static final String MESSAGE = "hello world (" + System.nanoTime() + ")"; + public static void main(String[] args) throws Exception { - if (isWindows()) { - System.out.println("The test only run on non-Windows OS. Bye."); - return; - } MulticastSocket msock = null; List failedGroups = new ArrayList(); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/MulticastSocket/PromiscuousIPv6.java openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/PromiscuousIPv6.java --- openjdk-21-21.0.8+9/test/jdk/java/net/MulticastSocket/PromiscuousIPv6.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/PromiscuousIPv6.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -24,7 +24,9 @@ /* * @test * @bug 8215294 - * @requires os.family == "linux" + * @requires os.family == "linux" & !(os.version ~= "3\\.10\\.0.*") + * @comment This test should only be run on Linux. + * The behavior under test is known NOT to work on Linux 3.10.0* kernels. * @library /test/lib * @build jdk.test.lib.NetworkConfiguration * PromiscuousIPv6 @@ -148,18 +150,6 @@ } public static void main(String args[]) throws IOException { - String os = System.getProperty("os.name"); - - if (!os.equals("Linux")) { - throw new SkippedException("This test should be run only on Linux"); - } else { - String osVersion = System.getProperty("os.version"); - String prefix = "3.10.0"; - if (osVersion.startsWith(prefix)) { - throw new SkippedException( - String.format("The behavior under test is known NOT to work on '%s' kernels", prefix)); - } - } NetworkConfiguration.printSystemConfiguration(System.out); List nifs = NetworkConfiguration.probe() diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/MulticastSocket/SetOutgoingIf.java openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/SetOutgoingIf.java --- openjdk-21-21.0.8+9/test/jdk/java/net/MulticastSocket/SetOutgoingIf.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/MulticastSocket/SetOutgoingIf.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -24,9 +24,10 @@ /* * @test * @bug 4742177 8241786 + * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code + * @requires os.family != "windows" * @library /test/lib * @run main/othervm SetOutgoingIf - * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code */ import java.io.IOException; import java.net.*; @@ -36,7 +37,7 @@ public class SetOutgoingIf implements AutoCloseable { - private static String osname; + private final MulticastSocket SOCKET; private final int PORT; private final Map sendersMap = new ConcurrentHashMap<>(); @@ -49,12 +50,6 @@ } } - static boolean isWindows() { - if (osname == null) - osname = System.getProperty("os.name"); - return osname.contains("Windows"); - } - static boolean isMacOS() { return System.getProperty("os.name").contains("OS X"); } @@ -82,10 +77,6 @@ } public void run() throws Exception { - if (isWindows()) { - System.out.println("The test only run on non-Windows OS. Bye."); - return; - } if (!hasIPv6()) { System.out.println("No IPv6 available. Bye."); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/ServerSocket/AnotherSelectFdsLimit.java openjdk-21-21.0.9+10/test/jdk/java/net/ServerSocket/AnotherSelectFdsLimit.java --- openjdk-21-21.0.8+9/test/jdk/java/net/ServerSocket/AnotherSelectFdsLimit.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/ServerSocket/AnotherSelectFdsLimit.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -25,6 +25,7 @@ * @test * @bug 8035897 * @summary FD_SETSIZE should be set on macosx + * @requires os.family == "mac" * @run main/othervm AnotherSelectFdsLimit 1023 * @run main/othervm AnotherSelectFdsLimit 1024 * @run main/othervm AnotherSelectFdsLimit 1025 @@ -41,10 +42,6 @@ static final int DEFAULT_FDS_TO_USE = 1600; public static void main(String [] args) throws Exception { - if (!System.getProperty("os.name").contains("OS X")) { - System.out.println("Test only run on MAC. Exiting."); - return; - } int fdsToUse = DEFAULT_FDS_TO_USE; if (args.length == 1) diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/ServerSocket/SelectFdsLimit.java openjdk-21-21.0.9+10/test/jdk/java/net/ServerSocket/SelectFdsLimit.java --- openjdk-21-21.0.8+9/test/jdk/java/net/ServerSocket/SelectFdsLimit.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/ServerSocket/SelectFdsLimit.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, 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 @@ -27,6 +27,7 @@ * @summary The total number of file descriptors is limited to * 1024(FDSET_SIZE) on MacOSX (the size of fd array passed to select() * call in java.net classes is limited to this value). + * @requires os.family == "mac" * @run main/othervm SelectFdsLimit * @author aleksej.efimov@oracle.com */ @@ -35,7 +36,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.net.ServerSocket; import java.net.SocketTimeoutException; @@ -72,12 +72,6 @@ public static void main(String [] args) throws IOException, FileNotFoundException { - //The bug 8021820 is a Mac specific and because of that test will pass on all - //other platforms - if (!System.getProperty("os.name").contains("OS X")) { - return; - } - //Create test directory with test files prepareTestEnv(); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/URLConnection/UNCTest.java openjdk-21-21.0.9+10/test/jdk/java/net/URLConnection/UNCTest.java --- openjdk-21-21.0.8+9/test/jdk/java/net/URLConnection/UNCTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/URLConnection/UNCTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -25,17 +25,46 @@ * @test * @bug 4401485 * @requires (os.family == "windows") + * @modules java.base/sun.net.www.protocol.file + * @library /test/lib * @summary Check that URL.openConnection() doesn't open connection to UNC - * @run main UNCTest file://jdk/LOCAL-JAVA/jdk1.4/win/README.txt */ +import jtreg.SkippedException; +import sun.net.www.protocol.file.FileURLConnection; + +import java.io.File; +import java.net.InetAddress; +import java.net.URI; import java.net.URL; import java.net.URLConnection; public class UNCTest { - public static void main(String args[]) throws Exception { - URL url = new URL( args[0] ); + public static void main(String[] args) throws Exception { + // Get the "computer name" for this host + String hostName = InetAddress.getLocalHost().getHostName(); + + // UNC path which always exists with Administrative Shares enabled + String path = "\\\\" + hostName + "\\C$\\Windows"; + + // Skip test if Administrative Shares is disabled + if (! new File(path).exists()) { + throw new SkippedException("Administrative Shares not enabled"); + } + + // File URL for the UNC path + URL url = new URI("file://" + hostName + "/C$/Windows").toURL(); + + // Should open a FileURLConnection for the UNC path URLConnection conn = url.openConnection(); + + // Sanity check that the connection is a FileURLConnection + if (! (conn instanceof FileURLConnection)) { + throw new Exception("Expected FileURLConnection, instead got " + + conn.getClass().getName()); + } + + // Verify that the connection is not in an already connected state conn.setRequestProperty( "User-Agent", "Java" ); } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/AbstractConnectTimeoutHandshake.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/AbstractConnectTimeoutHandshake.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/AbstractConnectTimeoutHandshake.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/AbstractConnectTimeoutHandshake.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -44,10 +44,11 @@ import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; + +import jdk.test.lib.net.URIBuilder; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; -import static java.lang.String.format; import static java.lang.System.out; import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpClient.Version.HTTP_1_1; @@ -56,7 +57,7 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; import static org.testng.Assert.fail; -public abstract class AbstractConnectTimeoutHandshake { +abstract class AbstractConnectTimeoutHandshake { // The number of iterations each testXXXClient performs. static final int TIMES = 2; @@ -197,15 +198,15 @@ // -- Infrastructure - static String serverAuthority(Server server) { - return InetAddress.getLoopbackAddress().getHostName() + ":" - + server.getPort(); - } - @BeforeTest public void setup() throws Exception { server = new Server(); - httpsURI = URI.create("https://" + serverAuthority(server) + "/foo"); + httpsURI = URIBuilder.newBuilder() + .scheme("https") + .loopback() + .port(server.getPort()) + .path("/foo") + .build(); out.println("HTTPS URI: " + httpsURI); } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/AsyncShutdownNow.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/AsyncShutdownNow.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/AsyncShutdownNow.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/AsyncShutdownNow.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -208,7 +208,7 @@ Thread.sleep(sleep); } if (i == step) { - out.printf("%d: shutting down client now%n", i, sleep); + out.printf("%d: shutting down client now%n", i); client.shutdownNow(); } var cf = bodyCF.exceptionally((t) -> { @@ -304,7 +304,7 @@ Thread.sleep(sleep); } if (i == step) { - out.printf("%d: shutting down client now%n", i, sleep); + out.printf("%d: shutting down client now%n", i); client.shutdownNow(); } bodyCF.handle((r, t) -> { diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -29,6 +29,8 @@ * @test * @summary Tests connection timeouts during SSL handshake * @bug 8208391 + * @library /test/lib + * @build AbstractConnectTimeoutHandshake * @run testng/othervm ConnectTimeoutHandshakeAsync */ diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -29,6 +29,8 @@ * @test * @summary Tests connection timeouts during SSL handshake * @bug 8208391 + * @library /test/lib + * @build AbstractConnectTimeoutHandshake * @run testng/othervm ConnectTimeoutHandshakeSync */ diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/HttpClientShutdown.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/HttpClientShutdown.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/HttpClientShutdown.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/HttpClientShutdown.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -192,7 +192,7 @@ out.println(now() + step + ": Got response: " + response); assertEquals(response.statusCode(), 200); } catch (AssertionError error) { - out.printf(now() + "%s: Closing body due to assertion - %s", error); + out.printf(now() + "%s: Closing body due to assertion - %s", step, error); ensureClosed(this); throw error; } @@ -276,7 +276,7 @@ continue; } if (i == step) { - out.printf(now() + "%d: shutting down client%n", i, sleep); + out.printf(now() + "%d: shutting down client%n", i); client.shutdown(); } var cf = bodyCF.exceptionally((t) -> { @@ -375,7 +375,7 @@ continue; } if (i == step) { - out.printf(now() + "%d: shutting down client%n", i, sleep); + out.printf(now() + "%d: shutting down client%n", i); client.shutdown(); } bodyCF.handle((r, t) -> { diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/ShutdownNow.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ShutdownNow.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/ShutdownNow.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/ShutdownNow.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -182,7 +182,7 @@ Thread.sleep(sleep); } if (i == step) { - out.printf("%d: shutting down client now%n", i, sleep); + out.printf("%d: shutting down client now%n", i); client.shutdownNow(); } final int si = i; @@ -238,7 +238,7 @@ Thread.sleep(sleep); } if (i == step) { - out.printf("%d: shutting down client now%n", i, sleep); + out.printf("%d: shutting down client now%n", i); client.shutdownNow(); } final int si = i; diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/http2/BasicTest.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/BasicTest.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/http2/BasicTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/BasicTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -24,9 +24,14 @@ /* * @test * @bug 8087112 - * @library /test/lib /test/jdk/java/net/httpclient/lib - * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil - * jdk.httpclient.test.lib.http2.Http2TestServer + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * @build jdk.httpclient.test.lib.http2.Http2TestServer + * jdk.httpclient.test.lib.http2.Http2TestExchange + * jdk.httpclient.test.lib.http2.Http2EchoHandler + * jdk.test.lib.Asserts + * jdk.test.lib.Utils + * jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors BasicTest */ @@ -44,17 +49,23 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -import jdk.httpclient.test.lib.common.TestUtil; import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.httpclient.test.lib.http2.Http2TestExchange; -import jdk.httpclient.test.lib.http2.Http2Handler; import jdk.httpclient.test.lib.http2.Http2EchoHandler; import jdk.test.lib.net.SimpleSSLContext; import org.testng.annotations.Test; + import static java.net.http.HttpClient.Version.HTTP_2; +import static jdk.test.lib.Asserts.assertFileContentsEqual; +import static jdk.test.lib.Utils.createTempFile; +import static jdk.test.lib.Utils.createTempFileOfSize; @Test public class BasicTest { + + private static final String TEMP_FILE_PREFIX = + HttpClient.class.getPackageName() + '-' + BasicTest.class.getSimpleName() + '-'; + static int httpPort, httpsPort; static Http2TestServer httpServer, httpsServer; static HttpClient client = null; @@ -184,14 +195,6 @@ } } - static Void compareFiles(Path path1, Path path2) { - return TestUtil.compareFiles(path1, path2); - } - - static Path tempFile() { - return TestUtil.tempFile(); - } - static final String SIMPLE_STRING = "Hello world Goodbye world"; static final int LOOPS = 13; @@ -202,7 +205,7 @@ System.err.printf("streamTest %b to %s\n" , secure, uri); HttpClient client = getClient(); - Path src = TestUtil.getAFile(FILESIZE * 4); + Path src = createTempFileOfSize(TEMP_FILE_PREFIX, null, FILESIZE * 4); HttpRequest req = HttpRequest.newBuilder(uri) .POST(BodyPublishers.ofFile(src)) .build(); @@ -216,7 +219,7 @@ return resp.body(); }); response.join(); - compareFiles(src, dest); + assertFileContentsEqual(src, dest); System.err.println("streamTest: DONE"); } @@ -269,17 +272,19 @@ // Do loops asynchronously CompletableFuture[] responses = new CompletableFuture[LOOPS]; - final Path source = TestUtil.getAFile(FILESIZE); + final Path source = createTempFileOfSize(TEMP_FILE_PREFIX, null, FILESIZE); HttpRequest request = HttpRequest.newBuilder(uri) .POST(BodyPublishers.ofFile(source)) .build(); for (int i = 0; i < LOOPS; i++) { - responses[i] = client.sendAsync(request, BodyHandlers.ofFile(tempFile())) + responses[i] = client.sendAsync(request, BodyHandlers.ofFile(createTempFile(TEMP_FILE_PREFIX, null))) //.thenApply(resp -> compareFiles(resp.body(), source)); .thenApply(resp -> { + Path body = resp.body(); System.out.printf("Resp status %d body size %d\n", - resp.statusCode(), resp.body().toFile().length()); - return compareFiles(resp.body(), source); + resp.statusCode(), body.toFile().length()); + assertFileContentsEqual(body, source); + return null; }); Thread.sleep(100); } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -24,9 +24,13 @@ /* * @test * @bug 8087112 8177935 - * @library /test/lib /test/jdk/java/net/httpclient/lib - * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil - * jdk.httpclient.test.lib.http2.Http2TestServer + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * @build jdk.httpclient.test.lib.http2.Http2TestServer + * jdk.httpclient.test.lib.http2.Http2EchoHandler + * jdk.test.lib.Asserts + * jdk.test.lib.Utils + * jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors FixedThreadPoolTest */ @@ -37,16 +41,23 @@ import javax.net.ssl.*; import java.nio.file.*; import java.util.concurrent.*; -import jdk.httpclient.test.lib.common.TestUtil; import jdk.httpclient.test.lib.http2.Http2TestServer; -import jdk.httpclient.test.lib.http2.Http2TestExchange; import jdk.httpclient.test.lib.http2.Http2EchoHandler; import jdk.test.lib.net.SimpleSSLContext; + import static java.net.http.HttpClient.Version.HTTP_2; +import static jdk.test.lib.Asserts.assertFileContentsEqual; +import static jdk.test.lib.Utils.createTempFile; +import static jdk.test.lib.Utils.createTempFileOfSize; + import org.testng.annotations.Test; @Test public class FixedThreadPoolTest { + + private static final String TEMP_FILE_PREFIX = + HttpClient.class.getPackageName() + '-' + FixedThreadPoolTest.class.getSimpleName() + '-'; + static int httpPort, httpsPort; static Http2TestServer httpServer, httpsServer; static HttpClient client = null; @@ -142,14 +153,6 @@ } } - static Void compareFiles(Path path1, Path path2) { - return TestUtil.compareFiles(path1, path2); - } - - static Path tempFile() { - return TestUtil.tempFile(); - } - static final String SIMPLE_STRING = "Hello world Goodbye world"; static final int LOOPS = 32; @@ -160,7 +163,7 @@ System.err.printf("streamTest %b to %s\n" , secure, uri); HttpClient client = getClient(); - Path src = TestUtil.getAFile(FILESIZE * 4); + Path src = createTempFileOfSize(TEMP_FILE_PREFIX, null, FILESIZE * 4); HttpRequest req = HttpRequest.newBuilder(uri) .POST(BodyPublishers.ofFile(src)) .build(); @@ -174,7 +177,7 @@ return resp.body(); }); response.join(); - compareFiles(src, dest); + assertFileContentsEqual(src, dest); System.err.println("DONE"); } @@ -239,17 +242,19 @@ // Do loops asynchronously CompletableFuture[] responses = new CompletableFuture[LOOPS]; - final Path source = TestUtil.getAFile(FILESIZE); + final Path source = createTempFileOfSize(TEMP_FILE_PREFIX, null, FILESIZE); HttpRequest request = HttpRequest.newBuilder(uri) .POST(BodyPublishers.ofFile(source)) .build(); for (int i = 0; i < LOOPS; i++) { - responses[i] = client.sendAsync(request, BodyHandlers.ofFile(tempFile())) + responses[i] = client.sendAsync(request, BodyHandlers.ofFile(createTempFile(TEMP_FILE_PREFIX, null))) //.thenApply(resp -> compareFiles(resp.body(), source)); .thenApply(resp -> { + Path body = resp.body(); System.out.printf("Resp status %d body size %d\n", - resp.statusCode(), resp.body().toFile().length()); - return compareFiles(resp.body(), source); + resp.statusCode(), body.toFile().length()); + assertFileContentsEqual(body, source); + return null; }); } CompletableFuture.allOf(responses).join(); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/http2/ServerPush.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/ServerPush.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/http2/ServerPush.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/http2/ServerPush.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -24,9 +24,11 @@ /* * @test * @bug 8087112 8159814 - * @library /test/lib /test/jdk/java/net/httpclient/lib - * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer - * jdk.httpclient.test.lib.common.TestUtil jdk.httpclient.test.lib.http2.PushHandler + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * @build jdk.httpclient.test.lib.http2.Http2TestServer + * jdk.httpclient.test.lib.http2.PushHandler + * jdk.test.lib.Utils * @run testng/othervm * -Djdk.httpclient.HttpClient.log=errors,requests,responses * ServerPush @@ -44,19 +46,21 @@ import java.util.*; import java.util.concurrent.*; import java.util.function.Consumer; -import jdk.httpclient.test.lib.common.TestUtil; import jdk.httpclient.test.lib.http2.Http2TestServer; -import jdk.httpclient.test.lib.http2.Http2TestExchange; -import jdk.httpclient.test.lib.http2.Http2Handler; import jdk.httpclient.test.lib.http2.PushHandler; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; + import static java.nio.charset.StandardCharsets.UTF_8; +import static jdk.test.lib.Utils.createTempFileOfSize; import static org.testng.Assert.*; public class ServerPush { + private static final String TEMP_FILE_PREFIX = + HttpClient.class.getPackageName() + '-' + ServerPush.class.getSimpleName() + '-'; + static final int LOOPS = 13; static final int FILE_SIZE = 512 * 1024 + 343; @@ -67,7 +71,7 @@ @BeforeTest public void setup() throws Exception { - tempFile = TestUtil.getAFile(FILE_SIZE); + tempFile = createTempFileOfSize(TEMP_FILE_PREFIX, null, FILE_SIZE); server = new Http2TestServer(false, 0); server.addHandler(new PushHandler(tempFile, LOOPS), "/"); System.out.println("Using temp file:" + tempFile); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java 2025-10-13 07:49:24.000000000 +0000 @@ -765,7 +765,7 @@ /** * A version agnostic adapter class for HTTP Servers. */ - public static abstract class HttpTestServer { + abstract class HttpTestServer implements AutoCloseable { private static final class ServerLogging { private static final Logger logger = Logger.getLogger("com.sun.net.httpserver"); static void enableLogging() { @@ -782,6 +782,11 @@ public abstract Version getVersion(); public abstract void setRequestApprover(final Predicate approver); + @Override + public void close() throws Exception { + stop(); + } + public String serverAuthority() { InetSocketAddress address = getAddress(); String hostString = address.getHostString(); @@ -971,6 +976,13 @@ System.out.println("Http2TestServerImpl: stop"); impl.stop(); } + + @Override + public void close() throws Exception { + System.out.println("Http2TestServerImpl: close"); + impl.close(); + } + @Override public HttpTestContext addHandler(HttpTestHandler handler, String path) { System.out.println("Http2TestServerImpl[" + getAddress() diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/TestUtil.java openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/TestUtil.java --- openjdk-21-21.0.8+9/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/TestUtil.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/TestUtil.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2015, 2023, 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 jdk.httpclient.test.lib.common; - -import java.io.*; -import java.nio.file.*; -import java.util.Arrays; - -public class TestUtil { - - static final Path CWD = Paths.get("."); - final static String fileContent = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // repeated - - public static Path getAFile(int size) throws IOException { - Path p = tempFile(); - BufferedWriter writer = Files.newBufferedWriter(p); - int len = fileContent.length(); - int iterations = size / len; - int remainder = size - (iterations * len); - for (int i=0; i newRequestApprover; - private static ThreadFactory defaultThreadFac = - (Runnable r) -> { - Thread t = new Thread(r); - t.setName("Test-server-pool"); - return t; - }; - - - private static ExecutorService getDefaultExecutor() { - return Executors.newCachedThreadPool(defaultThreadFac); + private static ExecutorService createExecutor(String name) { + String threadNamePrefix = "%s-pool".formatted(name); + ThreadFactory threadFactory = Thread.ofPlatform().name(threadNamePrefix, 0).factory(); + return Executors.newCachedThreadPool(threadFactory); } public Http2TestServer(String serverName, boolean secure, int port) throws Exception { - this(serverName, secure, port, getDefaultExecutor(), 50, null, null); + this(serverName, secure, port, null, 50, null, null); } public Http2TestServer(boolean secure, int port) throws Exception { - this(null, secure, port, getDefaultExecutor(), 50, null, null); + this(null, secure, port, null, 50, null, null); } public InetSocketAddress getAddress() { @@ -197,7 +192,7 @@ server = initPlaintext(port, backlog); } this.secure = secure; - this.exec = exec == null ? getDefaultExecutor() : exec; + this.exec = exec == null ? createExecutor(name) : exec; this.handlers = Collections.synchronizedMap(new HashMap<>()); this.properties = properties == null ? new Properties() : properties; this.connections = ConcurrentHashMap.newKeySet(); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/net/ipv6tests/TcpTest.java openjdk-21-21.0.9+10/test/jdk/java/net/ipv6tests/TcpTest.java --- openjdk-21-21.0.8+9/test/jdk/java/net/ipv6tests/TcpTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/net/ipv6tests/TcpTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -31,6 +31,7 @@ * @library /test/lib * @build jdk.test.lib.NetworkConfiguration * jdk.test.lib.Platform + * jtreg.SkippedException * @run main TcpTest -d */ @@ -38,6 +39,8 @@ import java.io.*; import java.util.concurrent.TimeUnit; +import jtreg.SkippedException; + public class TcpTest extends Tests { static ServerSocket server, server1, server2; static Socket c1, c2, c3, s1, s2, s3; @@ -62,12 +65,10 @@ public static void main (String[] args) throws Exception { checkDebug(args); if (ia4addr == null) { - System.out.println ("No IPV4 addresses: exiting test"); - return; + throw new SkippedException("No IPV4 addresses: exiting test"); } if (ia6addr == null) { - System.out.println ("No IPV6 addresses: exiting test"); - return; + throw new SkippedException("No IPV6 addresses: exiting test"); } dprintln ("Local Addresses"); dprintln (ia4addr.toString()); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/nio/charset/Charset/Contains.java openjdk-21-21.0.9+10/test/jdk/java/nio/charset/Charset/Contains.java --- openjdk-21-21.0.8+9/test/jdk/java/nio/charset/Charset/Contains.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/nio/charset/Charset/Contains.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2023, 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 @@ -23,7 +23,7 @@ /* @test * @summary Unit test for charset containment - * @bug 6798572 + * @bug 6798572 8167252 * @modules jdk.charsets */ @@ -93,6 +93,8 @@ ck(cp1252, cp1252, true); checkUTF(); + + containsSelfTest(); } static void checkUTF() throws Exception { @@ -103,6 +105,27 @@ true); } + /** + * Tests the assertion in the contains() method: "Every charset contains itself." + */ + static void containsSelfTest() { + boolean failed = false; + + for (var entry : Charset.availableCharsets().entrySet()) { + Charset charset = entry.getValue(); + boolean contains = charset.contains(charset); + + System.out.println("Charset(" + charset.name() + ").contains(Charset(" + charset.name() + + ")) returns " + contains); + if (!contains) { + failed = true; + } + } + if (failed) { + throw new RuntimeException("Charset.contains(itself) returns false for some charsets"); + } + } + static String[] utfNames = {"utf-16", "utf-8", "utf-16le", diff -Nru openjdk-21-21.0.8+9/test/jdk/java/security/cert/CertificateFactory/SlowStream.java openjdk-21-21.0.9+10/test/jdk/java/security/cert/CertificateFactory/SlowStream.java --- openjdk-21-21.0.8+9/test/jdk/java/security/cert/CertificateFactory/SlowStream.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/security/cert/CertificateFactory/SlowStream.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, 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 @@ -21,31 +21,74 @@ * questions. */ -import java.io.*; -import java.security.cert.*; +/* + * @test + * @bug 6813340 + * @summary X509Factory should not depend on is.available()==0 + */ -class SlowStreamReader { +import java.io.File; +import java.io.FileInputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.security.cert.CertificateFactory; +import java.util.concurrent.atomic.AtomicBoolean; +public class SlowStream { public static void main(String[] args) throws Exception { - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - if (factory.generateCertificates(System.in).size() != 5) { - throw new Exception("Not all certs read"); - } - } -} + final var outputStream = new PipedOutputStream(); + final var inputStream = new PipedInputStream(outputStream); -class SlowStreamWriter { - public static void main(String[] args) throws Exception { - for (int i=0; i<5; i++) { - FileInputStream fin = new FileInputStream(new File(new File( - System.getProperty("test.src", "."), "openssl"), "pem")); - byte[] buffer = new byte[4096]; - while (true) { - int len = fin.read(buffer); - if (len < 0) break; - System.out.write(buffer, 0, len); + final var failed = new AtomicBoolean(false); + + final var writer = new Thread(() -> { + try { + for (int i = 0; i < 5; i++) { + try (final var fin = new FileInputStream(new File( + new File(System.getProperty("test.src", "."), + "openssl"), + "pem"))) { + + fin.transferTo(outputStream); + + Thread.sleep(2000); + } + } + outputStream.close(); + } catch (final Exception e) { + System.out.println("Writer Thread Error: "); + e.printStackTrace(System.out); + failed.set(true); + } + }); + + final var reader = new Thread(() -> { + try { + final var factory = CertificateFactory.getInstance("X.509"); + final var numOfCerts = factory.generateCertificates(inputStream).size(); + if (numOfCerts != 5) { + throw new Exception( + String.format("Not all certs read. %d found 5 expected", numOfCerts) + ); + } + inputStream.close(); + } catch (final Exception e) { + System.out.println("Reader Thread Error: "); + e.printStackTrace(System.out); + failed.set(true); } - Thread.sleep(2000); + }); + + writer.start(); + reader.start(); + + writer.join(); + reader.join(); + + if (failed.get()) { + throw new RuntimeException( + "The test failed, please check the reader and writer threads output" + ); } } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/security/cert/CertificateFactory/slowstream.sh openjdk-21-21.0.9+10/test/jdk/java/security/cert/CertificateFactory/slowstream.sh --- openjdk-21-21.0.8+9/test/jdk/java/security/cert/CertificateFactory/slowstream.sh 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/security/cert/CertificateFactory/slowstream.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -# -# Copyright (c) 2010, 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 6813340 -# @summary X509Factory should not depend on is.available()==0 - -if [ "${TESTSRC}" = "" ] ; then - TESTSRC="." -fi -if [ "${TESTJAVA}" = "" ] ; then - echo "TESTJAVA not set. Test cannot execute." - echo "FAILED!!!" - exit 1 -fi -if [ "${COMPILEJAVA}" = "" ]; then - COMPILEJAVA="${TESTJAVA}" -fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - Windows_* ) - FS="\\" - ;; - * ) - FS="/" - ;; -esac - -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ - ${TESTSRC}${FS}SlowStream.java -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${TESTJAVAOPTS} -Dtest.src=${TESTSRC} SlowStreamWriter | \ - ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${TESTJAVAOPTS} SlowStreamReader diff -Nru openjdk-21-21.0.8+9/test/jdk/java/text/Format/MessageFormat/SerializationTest.java openjdk-21-21.0.9+10/test/jdk/java/text/Format/MessageFormat/SerializationTest.java --- openjdk-21-21.0.8+9/test/jdk/java/text/Format/MessageFormat/SerializationTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/text/Format/MessageFormat/SerializationTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -23,7 +23,7 @@ /* * @test - * @bug 8331446 + * @bug 8331446 8340554 * @summary Check correctness of deserialization * @run junit SerializationTest */ @@ -70,7 +70,13 @@ // With null locale. (NPE not thrown, if no format defined) new MessageFormat("{1} {0} foo", null), // With formats - new MessageFormat("{0,number,short} {0} {1,date,long} foo") + new MessageFormat("{0,number,short} {0} {1,date,long} foo"), + // Offset equal to pattern length (0) + new MessageFormat("{0}"), + // Offset equal to pattern length (1) + new MessageFormat("X{0}"), + // Offset 1 under pattern length + new MessageFormat("X{0}X") ); } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/util/Currency/CurrencyTest.java openjdk-21-21.0.9+10/test/jdk/java/util/Currency/CurrencyTest.java --- openjdk-21-21.0.8+9/test/jdk/java/util/Currency/CurrencyTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/util/Currency/CurrencyTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -25,7 +25,7 @@ * @test * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531 * 6488442 7036905 8008577 8039317 8074350 8074351 8150324 8167143 - * 8264792 8334653 + * 8264792 8334653 8353713 * @summary Basic tests for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -80,14 +80,41 @@ // Calling getInstance() with an invalid currency code should throw an IAE @ParameterizedTest - @MethodSource("invalidCurrencies") + @MethodSource("non4217Currencies") public void invalidCurrencyTest(String currencyCode) { - assertThrows(IllegalArgumentException.class, () -> + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(currencyCode), "getInstance() did not throw IAE"); + assertEquals("The input currency code: \"%s\" is not a valid ISO 4217 code" + .formatted(currencyCode), ex.getMessage()); } - private static Stream invalidCurrencies() { - return Stream.of("AQD", "US$", "\u20AC"); + private static Stream non4217Currencies() { + return Stream.of("AQD", "US$"); + } + + // Provide 3 length code, but first 2 chars should not be able to index + // the main table, thus resulting as incorrect country code + @Test + void invalidCountryInCodeTest() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Currency.getInstance("..A"), "getInstance() did not throw IAE"); + assertEquals("The country code: \"%s\" is not a valid ISO 3166 code" + .formatted(".."), ex.getMessage()); + } + + // Calling getInstance() with a currency code not 3 characters long should throw + // an IAE + @ParameterizedTest + @MethodSource("invalidLengthCurrencies") + public void invalidCurrencyLengthTest(String currencyCode) { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Currency.getInstance(currencyCode), "getInstance() did not throw IAE"); + assertEquals("The input currency code: \"%s\" must have a length of 3 characters" + .formatted(currencyCode), ex.getMessage()); + } + + private static Stream invalidLengthCurrencies() { + return Stream.of("\u20AC", "", "12345"); } } @@ -144,7 +171,10 @@ ctryLength == 3 || // UN M.49 code ctryCode.matches("AA|Q[M-Z]|X[A-JL-Z]|ZZ" + // user defined codes, excluding "XK" (Kosovo) "AC|CP|DG|EA|EU|FX|IC|SU|TA|UK")) { // exceptional reservation codes - assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(locale), "Did not throw IAE"); + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, + () -> Currency.getInstance(locale), "Did not throw IAE"); + assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code" + .formatted(locale), ex.getMessage()); } else { goodCountries++; Currency currency = Currency.getInstance(locale); @@ -160,11 +190,15 @@ } } - // Check an invalid country code + // Check an invalid country code supplied via the region override @Test - public void invalidCountryTest() { - assertThrows(IllegalArgumentException.class, ()-> - Currency.getInstance(Locale.of("", "EU")), "Did not throw IAE"); + public void invalidCountryRegionOverrideTest() { + // Override US with nonsensical country + var loc = Locale.forLanguageTag("en-US-u-rg-XXzzzz"); + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, + ()-> Currency.getInstance(loc), "Did not throw IAE"); + assertEquals("The country of the input locale: \"%s\" is not a valid ISO 3166 country code" + .formatted(loc), ex.getMessage()); } // Ensure a selection of countries have the expected currency diff -Nru openjdk-21-21.0.8+9/test/jdk/java/util/Currency/ISO4217-list-one.txt openjdk-21-21.0.9+10/test/jdk/java/util/Currency/ISO4217-list-one.txt --- openjdk-21-21.0.8+9/test/jdk/java/util/Currency/ISO4217-list-one.txt 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/util/Currency/ISO4217-list-one.txt 2025-10-13 07:49:24.000000000 +0000 @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 179 -# (As of 02 May 2025) +# Amendments up until ISO 4217 AMENDMENT NUMBER 180 +# (As of 22 September 2025) # # Version FILEVERSION=3 -DATAVERSION=179 +DATAVERSION=180 # ISO 4217 currency data AF AFN 971 2 @@ -44,7 +44,7 @@ BR BRL 986 2 IO USD 840 2 BN BND 96 2 -BG BGN 975 2 +BG BGN 975 2 2025-12-31-22-00-00 EUR 978 2 BF XOF 952 0 BI BIF 108 0 KH KHR 116 2 @@ -69,7 +69,7 @@ CI XOF 952 0 HR EUR 978 2 CU CUP 192 2 -CW ANG 532 2 2025-04-01-04-00-00 XCG 532 2 +CW XCG 532 2 CY EUR 978 2 CZ CZK 203 2 DK DKK 208 2 @@ -233,7 +233,7 @@ SD SDG 938 2 SR SRD 968 2 SJ NOK 578 2 -SX ANG 532 2 2025-04-01-04-00-00 XCG 532 2 +SX XCG 532 2 SZ SZL 748 2 SE SEK 752 2 CH CHF 756 2 diff -Nru openjdk-21-21.0.8+9/test/jdk/java/util/Currency/ValidateISO4217.java openjdk-21-21.0.9+10/test/jdk/java/util/Currency/ValidateISO4217.java --- openjdk-21-21.0.8+9/test/jdk/java/util/Currency/ValidateISO4217.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/util/Currency/ValidateISO4217.java 2025-10-13 07:49:24.000000000 +0000 @@ -26,7 +26,7 @@ * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 8334653 - * 8356096 + * 8356096 8368308 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -87,7 +87,7 @@ private static final Set testCurrencies = new HashSet<>(); // Codes that are obsolete, do not have related country, extra currency private static final String otherCodes = - "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-" + "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BGN-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-" + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-HRK-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAD-XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" diff -Nru openjdk-21-21.0.8+9/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java openjdk-21-21.0.9+10/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java --- openjdk-21-21.0.8+9/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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 @@ -25,9 +25,9 @@ * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 - * 8327631 8332424 8334418 8344589 + * 8327631 8332424 8334418 8344589 8348328 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2024-11-19) with Locale and Locale.LanguageRange + * (LSR Revision: 2025-05-15) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ @@ -45,9 +45,9 @@ static boolean err = false; private static final String ACCEPT_LANGUAGE = - "Accept-Language: aam, adp, aeb, ajs, aog, apc, ajp, aue, bcg, bic, bpp, cey, cbr, cnp, cqu, crr, csp, csx, dif, dmw, dsz, ehs, ema," - + " en-gb-oed, gti, iba, ilw, jks, kdz, kjh, kmb, koj, kru, ksp, kwq, kxe, kzk, lgs, lii, lmm, lsb, lsc, lsn, lsv, lsw, lvi, meg, mtm," - + " ngv, nns, ola, oyb, pat, pcr, phr, plu, pnd, pub, rib, rnb, rsn, scv, snz, sqx, suj, szy, taj, tdg, tjj, tjp, tpn, tvx," + "Accept-Language: aam, adp, aeb, ajs, aog, apc, ajp, aue, bcg, bic, bpp, cey, cbr, cnp, cqu, crr, csp, csx, dif, dmw, dsz, ehs, eko, ema," + + " en-gb-oed, gti, hnm, iba, ilw, jks, kdz, kjh, kmb, koj, kru, ksp, kwq, kxe, kzk, lgs, lii, lmm, lsb, lsc, lsn, lsv, lsw, luh, lvi, meg, mtm," + + " ngv, nns, ola, oyb, pat, pcr, phr, plu, pnd, pub, rib, rnb, rsn, scv, sjc, snz, sqm, sqx, suj, szy, taj, tdg, tjj, tjp, tpn, tvx," + " umi, uss, uth, xia, yos, ysm, zko, wkr;q=0.9, ar-hyw;q=0.8, yug;q=0.5, gfx;q=0.4"; private static final List EXPECTED_RANGE_LIST = List.of( new LanguageRange("aam", 1.0), @@ -94,12 +94,16 @@ new LanguageRange("sgn-dsz", 1.0), new LanguageRange("ehs", 1.0), new LanguageRange("sgn-ehs", 1.0), + new LanguageRange("eko", 1.0), + new LanguageRange("nte", 1.0), new LanguageRange("ema", 1.0), new LanguageRange("uok", 1.0), new LanguageRange("en-gb-oed", 1.0), new LanguageRange("en-gb-oxendict", 1.0), new LanguageRange("gti", 1.0), new LanguageRange("nyc", 1.0), + new LanguageRange("hnm", 1.0), + new LanguageRange("zh-hnm", 1.0), new LanguageRange("iba", 1.0), new LanguageRange("snb", 1.0), new LanguageRange("blg", 1.0), @@ -142,6 +146,8 @@ new LanguageRange("sgn-lsv", 1.0), new LanguageRange("lsw", 1.0), new LanguageRange("sgn-lsw", 1.0), + new LanguageRange("luh", 1.0), + new LanguageRange("zh-luh", 1.0), new LanguageRange("lvi", 1.0), new LanguageRange("meg", 1.0), new LanguageRange("cir", 1.0), @@ -176,8 +182,12 @@ new LanguageRange("sgn-rsn", 1.0), new LanguageRange("scv", 1.0), new LanguageRange("zir", 1.0), + new LanguageRange("sjc", 1.0), + new LanguageRange("zh-sjc", 1.0), new LanguageRange("snz", 1.0), new LanguageRange("asd", 1.0), + new LanguageRange("sqm", 1.0), + new LanguageRange("dek", 1.0), new LanguageRange("sqx", 1.0), new LanguageRange("sgn-sqx", 1.0), new LanguageRange("suj", 1.0), @@ -264,12 +274,18 @@ System.err.println(" Expected size=" + expectedSize); for (LanguageRange lr : expected) { + if (!got.contains(lr)) { + System.err.print("Error - Actual does not contain:"); + } System.err.println(" range=" + lr.getRange() + ", weight=" + lr.getWeight()); } System.err.println(" Actual size=" + actualSize); for (LanguageRange lr : got) { + if (!expected.contains(lr)) { + System.err.print("Error - Expected does not contain:"); + } System.err.println(" range=" + lr.getRange() + ", weight=" + lr.getWeight()); } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java openjdk-21-21.0.9+10/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java --- openjdk-21-21.0.8+9/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -130,7 +130,7 @@ String displayName = zi.getDisplayName(false, TimeZone.SHORT, Locale.US); Locale.setDefault(originalLocale); if (!displayName.equals("GMT+05:00")) { - System.err.printf("Wrong display name for timezone Etc/GMT-5 : expected GMT+05:00, Actual " + displayName); + System.err.println("Wrong display name for timezone Etc/GMT-5 : expected GMT+05:00, Actual " + displayName); errors++; } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java openjdk-21-21.0.9+10/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java --- openjdk-21-21.0.8+9/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -700,11 +700,13 @@ public void testShutdownNow_delayedTasks() throws InterruptedException { final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); List> tasks = new ArrayList<>(); + final int DELAY = 100; + for (int i = 0; i < 3; i++) { Runnable r = new NoOpRunnable(); - tasks.add(p.schedule(r, 9, SECONDS)); - tasks.add(p.scheduleAtFixedRate(r, 9, 9, SECONDS)); - tasks.add(p.scheduleWithFixedDelay(r, 9, 9, SECONDS)); + tasks.add(p.schedule(r, DELAY, SECONDS)); + tasks.add(p.scheduleAtFixedRate(r, DELAY, DELAY, SECONDS)); + tasks.add(p.scheduleWithFixedDelay(r, DELAY, DELAY, SECONDS)); } if (testImplementationDetails) assertEquals(new HashSet(tasks), new HashSet(p.getQueue())); diff -Nru openjdk-21-21.0.8+9/test/jdk/java/util/zip/EntryCount64k.java openjdk-21-21.0.9+10/test/jdk/java/util/zip/EntryCount64k.java --- openjdk-21-21.0.8+9/test/jdk/java/util/zip/EntryCount64k.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/util/zip/EntryCount64k.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Google Inc. All rights reserved. + * 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 @@ -47,9 +48,12 @@ import jdk.test.lib.process.ProcessTools; public class EntryCount64k { + + private static final String MAIN_CLASS_MSG = "foo bar hello world Main"; + public static class Main { public static void main(String[] args) { - System.out.print("Main"); + System.out.println(MAIN_CLASS_MSG); } } @@ -162,7 +166,10 @@ // Check java -jar OutputAnalyzer a = ProcessTools.executeTestJava("-jar", zipFile.getName()); a.shouldHaveExitValue(0); - a.stdoutShouldMatch("\\AMain\\Z"); + // expect the message from the application on stdout + a.stdoutContains(MAIN_CLASS_MSG); + // nothing is expected on stderr (apart from any probable deprecation + // warnings from the launcher/JVM) a.stderrShouldMatchIgnoreDeprecatedWarnings("\\A\\Z"); } } diff -Nru openjdk-21-21.0.8+9/test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java openjdk-21-21.0.9+10/test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java --- openjdk-21-21.0.8+9/test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023, 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 7036144 + * @summary Test concatenated gz streams when available() returns zero + * @run junit GZIPInputStreamAvailable + */ + +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +public class GZIPInputStreamAvailable { + + public static final int NUM_COPIES = 100; + + @Test + public void testZeroAvailable() throws IOException { + + // Create some uncompressed data and then repeat it NUM_COPIES times + byte[] uncompressed1 = "this is a test".getBytes("ASCII"); + byte[] uncompressedN = repeat(uncompressed1, NUM_COPIES); + + // Compress the original data and then repeat that NUM_COPIES times + byte[] compressed1 = deflate(uncompressed1); + byte[] compressedN = repeat(compressed1, NUM_COPIES); + + // (a) Read back inflated data from a stream where available() is accurate and verify + byte[] readback1 = inflate(new ByteArrayInputStream(compressedN)); + assertArrayEquals(uncompressedN, readback1); + + // (b) Read back inflated data from a stream where available() always returns zero and verify + byte[] readback2 = inflate(new ZeroAvailableStream(new ByteArrayInputStream(compressedN))); + assertArrayEquals(uncompressedN, readback2); + } + + public static byte[] repeat(byte[] data, int count) { + byte[] repeat = new byte[data.length * count]; + int off = 0; + for (int i = 0; i < count; i++) { + System.arraycopy(data, 0, repeat, off, data.length); + off += data.length; + } + return repeat; + } + + public static byte[] deflate(byte[] data) throws IOException { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + try (GZIPOutputStream out = new GZIPOutputStream(buf)) { + out.write(data); + } + return buf.toByteArray(); + } + + public static byte[] inflate(InputStream in) throws IOException { + return new GZIPInputStream(in).readAllBytes(); + } + + public static class ZeroAvailableStream extends FilterInputStream { + public ZeroAvailableStream(InputStream in) { + super(in); + } + @Override + public int available() { + return 0; + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/accessibility/TestPopupMenuChildCount.java openjdk-21-21.0.9+10/test/jdk/javax/accessibility/TestPopupMenuChildCount.java --- openjdk-21-21.0.8+9/test/jdk/javax/accessibility/TestPopupMenuChildCount.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/accessibility/TestPopupMenuChildCount.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025, 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.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +/* + * @test + * @bug 8341311 + * @summary Verifies that VoiceOver announces correct number of child for PopupMenu on macOS + * @requires os.family == "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestPopupMenuChildCount + */ + +public class TestPopupMenuChildCount { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is applicable only on macOS. + + Test UI contains an empty JFrame. On press of left/right mouse button, + a PopupMenu will be visible. + + Follow these steps to test the behaviour: + + 1. Start the VoiceOver (Press Command + F5) application + 2. Press Left/Right mouse button inside test frame window to open + the PopupMenu + 3. VO should announce "Menu" with number of child items of the Popupmenu + 4. Press Up/Down arrow to traverse popupmenu child items + 5. Press Right arrow key to open submenu + 6. VO should announce "Menu" with correct number of child items + for the submenu (For e.g. When Submenu-1 is open, VO should announce + "Menu 4 items") + 7. Repeat the process for other submenus + 8. Press Pass if you are able to hear correct announcements + else Fail"""; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(TestPopupMenuChildCount::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + JFrame frame = new JFrame("Test Frame"); + + JPopupMenu popupmenu = new JPopupMenu(); + JMenuItem mi1 = new JMenuItem("MenuItem-1"); + JMenuItem mi2 = new JMenuItem("MenuItem-2"); + JMenuItem mi3 = new JMenuItem("MenuItem-3"); + popupmenu.add(mi1); + popupmenu.add(mi2); + popupmenu.add(mi3); + + JMenu submenu1 = new JMenu("Submenu-1"); + submenu1.add("subOne"); + submenu1.add("subTwo"); + submenu1.add("subThree"); + + JMenu submenu2 = new JMenu("Submenu-2"); + submenu2.add("subOne"); + submenu2.add("subTwo"); + + JMenu submenu3 = new JMenu ("Submenu-3"); + submenu3.add("subOne"); + submenu1.add(submenu3); + + popupmenu.add(submenu1); + popupmenu.add(submenu2); + + frame.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + popupmenu.show(e.getComponent(), e.getX(), e.getY()); + } + }); + frame.setSize(300, 300); + return frame; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java openjdk-21-21.0.9+10/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java --- openjdk-21-21.0.8+9/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -29,14 +29,16 @@ * @run testng/othervm InconsistentEntries */ +import java.util.List; +import jdk.test.lib.Utils; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; import org.testng.Assert; -import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import javax.crypto.*; import java.io.File; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -45,42 +47,35 @@ public class InconsistentEntries { - private static final String JDK_HOME = System.getProperty("test.jdk"); - private static final String TEST_SRC = System.getProperty("test.src"); - private static final Path POLICY_DIR = Paths.get(JDK_HOME, "conf", "security", - "policy", "testlimited"); - private static final Path POLICY_FILE = Paths.get(TEST_SRC, "default_local.policy"); - - Path targetFile = null; + private static final String JDK_HOME = System.getProperty("test.jdk", "."); + private static final String TEST_SRC = System.getProperty("test.src", "."); + private static final Path TEMP_JDK_HOME = Path.of("java"); + private static final Path POLICY_DIR = TEMP_JDK_HOME.resolve(Path.of("conf", "security", + "policy", "testlimited")); + private static final Path POLICY_FILE_SRC = Paths.get(TEST_SRC, "default_local.policy"); + private static final Path POLICY_FILE_TARGET = POLICY_DIR + .resolve(POLICY_FILE_SRC.getFileName()); @BeforeTest - public void setUp() throws IOException { + public void setUp() throws Exception { + // Clone the tested JDK to the scratch directory + FileUtils.copyDirectory(Path.of(JDK_HOME), TEMP_JDK_HOME); + + // create policy directory in the cloned JDK if (!POLICY_DIR.toFile().exists()) { Files.createDirectory(POLICY_DIR); } - targetFile = POLICY_DIR.resolve(POLICY_FILE.getFileName()); - Files.copy(POLICY_FILE, targetFile, StandardCopyOption.REPLACE_EXISTING); - } - - @AfterTest - public void cleanUp() throws IOException { - Files.delete(targetFile); + // copy policy file into policy directory + Files.copy(POLICY_FILE_SRC, POLICY_FILE_TARGET, StandardCopyOption.REPLACE_EXISTING); } - @Test - public void test() throws Exception { - String JAVA_HOME = System.getProperty("java.home"); - String FS = System.getProperty("file.separator"); - Path testlimited = Path.of(JAVA_HOME + FS + "conf" + FS + "security" + - FS + "policy" + FS + "testlimited"); - if (!Files.exists(testlimited)) { + public static void main(String[] args) throws Throwable { + if (!Files.exists(POLICY_DIR)) { throw new RuntimeException( "custom policy subdirectory: testlimited does not exist"); } - - File testpolicy = new File(JAVA_HOME + FS + "conf" + FS + "security" + - FS + "policy" + FS + "testlimited" + FS + "default_local.policy"); + File testpolicy = new File(POLICY_FILE_TARGET.toString()); if (testpolicy.length() == 0) { throw new RuntimeException( "policy: default_local.policy does not exist or is empty"); @@ -91,4 +86,16 @@ Assert.assertThrows(ExceptionInInitializerError.class, () -> Cipher.getMaxAllowedKeyLength("AES")); } + + @Test + public void test() throws Exception { + String tmpJava = TEMP_JDK_HOME.resolve("bin").resolve("java").toString(); + String[] args = Utils.prependTestJavaOpts(InconsistentEntries.class.getName()); + ProcessBuilder pb = new ProcessBuilder(tmpJava); + pb.command().addAll(List.of(args)); + + ProcessTools + .executeProcess(pb) + .shouldHaveExitValue(0); + } } diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/management/remote/mandatory/notif/ListenerScaleTest.java openjdk-21-21.0.9+10/test/jdk/javax/management/remote/mandatory/notif/ListenerScaleTest.java --- openjdk-21-21.0.8+9/test/jdk/javax/management/remote/mandatory/notif/ListenerScaleTest.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/management/remote/mandatory/notif/ListenerScaleTest.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2023, 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 @@ -77,6 +77,7 @@ private static final int WARMUP_WITH_ONE_MBEAN = 1000; private static final int NOTIFS_TO_TIME = 100; private static final int EXTRA_MBEANS = 20000; + private static final double RATIO_FAIL_VALUE = 2500.0; private static final ObjectName testObjectName; static { @@ -187,8 +188,9 @@ long manyMBeansTime = timeNotif(mbs); System.out.println("Time with many MBeans: " + manyMBeansTime + "ns"); double ratio = (double) manyMBeansTime / singleMBeanTime; - if (ratio > 500.0) + if (ratio > RATIO_FAIL_VALUE) { throw new Exception("Failed: ratio=" + ratio); + } System.out.println("Test passed: ratio=" + ratio); } } diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java --- openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -105,6 +105,7 @@ (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); + sslServerSocket.setEnabledProtocols(new String[]{"TLSv1.2"}); serverPort = sslServerSocket.getLocalPort(); /* diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java --- openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * 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 + * @library /javax/net/ssl/templates + * @bug 8311644 + * @summary Verify CertificateMessage alerts are correct to the TLS specs + * @run main/othervm -Djdk.tls.client.protocols=TLSv1.2 CertMsgCheck handshake_failure + * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 CertMsgCheck certificate_required + * + */ + +public class CertMsgCheck { + + public static void main(String[] args) throws Exception { + // Start server + TLSBase.Server server = new TLSBase.ServerBuilder().setClientAuth(true). + build(); + + // Initial client session + TLSBase.Client client1 = new TLSBase.Client(true, false); + + server.getSession(client1).getSessionContext(); + server.done(); + + var eList = server.getExceptionList(); + System.out.println("Exception list size is " + eList.size()); + + for (Exception e : eList) { + System.out.println("Looking at " + e.getClass() + " " + + e.getMessage()); + if (e.getMessage().contains(args[0])) { + System.out.println("Found correct exception: " + args[0] + + " in " + e.getMessage()); + return; + } else { + System.out.println("No \"" + args[0] + "\" found."); + } + } + + throw new Exception("Failed to find expected alert: " + args[0]); + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java --- openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -36,15 +36,11 @@ */ import javax.net.ssl.SSLSession; +import java.util.HexFormat; public class CheckSessionContext { - static void toHex(byte[] id) { - for (byte b : id) { - System.out.printf("%02X ", b); - } - System.out.println(); - } + static HexFormat hex = HexFormat.of(); public static void main(String[] args) throws Exception { TLSBase.Server server = new TLSBase.Server(); @@ -52,20 +48,18 @@ // Initial client session TLSBase.Client client1 = new TLSBase.Client(); if (server.getSession(client1).getSessionContext() == null) { - throw new Exception("Context was null"); + throw new Exception("Context was null. Handshake failure."); } else { System.out.println("Context was found"); } SSLSession ss = server.getSession(client1); System.out.println(ss); byte[] id = ss.getId(); - System.out.print("id = "); - toHex(id); + System.out.println("id = " + hex.formatHex(id)); System.out.println("ss.getSessionContext().getSession(id) = " + ss.getSessionContext().getSession(id)); if (ss.getSessionContext().getSession(id) != null) { id = ss.getSessionContext().getSession(id).getId(); - System.out.print("id = "); - toHex(id); + System.out.println("id = " + hex.formatHex(id)); } server.close(client1); client1.close(); diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java --- openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/SSLEngineTemplate.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -31,6 +31,8 @@ * @build SSLContextTemplate * @run main/othervm SSLEngineTemplate */ + +import java.util.Objects; import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import java.nio.ByteBuffer; @@ -264,4 +266,75 @@ a.limit(a.capacity()); b.limit(b.capacity()); } + + /** + * Given a TLS record containing one or more handshake messages, return + * the specific handshake message as a ByteBuffer (a slice of the record) + * + * @param tlsRecord A ByteBuffer containing a TLS record. It is + * assumed that the position of the ByteBuffer is on the + * first byte of the TLS record header. + * @param hsMsgId The message identifier for the handshake message + * being sought. + * + * Message Identifiers + * + * @param isDtls Indicates whether DTLS protocol being used. + * @return a ByteBuffer containing the TLS handshake message. + * The position of the returned ByteBuffer will be on the + * first byte of the TLS handshake message data, + * immediately following the handshake header. + * If the message is not found, null will be returned. + * @throws SSLException if the incoming ByteBuffer does not contain + * a well-formed TLS message. + */ + protected static ByteBuffer extractHandshakeMsg( + ByteBuffer tlsRecord, int hsMsgId, boolean isDtls) + throws SSLException { + Objects.requireNonNull(tlsRecord); + tlsRecord.mark(); + + // Process the TLS record header + int type = Byte.toUnsignedInt(tlsRecord.get()); + int ver_major = Byte.toUnsignedInt(tlsRecord.get()); + int ver_minor = Byte.toUnsignedInt(tlsRecord.get()); + // Skip DTLS-specific bytes + if (isDtls) { + tlsRecord.position(tlsRecord.position() + 8); + } + int recLen = Short.toUnsignedInt(tlsRecord.getShort()); + + if (recLen > tlsRecord.remaining()) { + throw new SSLException("Incomplete record in buffer: " + + "Record length = " + recLen + + ", Remaining = " + + tlsRecord.remaining()); + } + + while (tlsRecord.hasRemaining()) { + // Grab the handshake message header. + int msgHdr = tlsRecord.getInt(); + int msgType = (msgHdr >> 24) & 0x000000FF; + int msgLen = msgHdr & 0x00FFFFFF; + // Skip DTLS-specific bytes + if (isDtls) { + tlsRecord.position(tlsRecord.position() + 8); + } + + if (msgType == hsMsgId) { + // Slice the buffer such that it contains the entire + // handshake message (less the handshake header). + ByteBuffer buf = tlsRecord.slice(tlsRecord.position(), msgLen); + tlsRecord.reset(); + return buf; + } else { + // Skip to the next handshake message, if there is one + tlsRecord.position(tlsRecord.position() + msgLen); + } + } + + tlsRecord.reset(); + return null; + } } diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java --- openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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 @@ -245,7 +245,7 @@ // // The server side takes care of the issue if the server cannot // get started in 90 seconds. The client side would just ignore - // the test case if the serer is not ready. + // the test case if the server is not ready. boolean serverIsReady = serverCondition.await(90L, TimeUnit.SECONDS); if (!serverIsReady) { @@ -378,7 +378,7 @@ * Check various exception conditions. */ if ((local != null) && (remote != null)) { - // If both failed, return the curthread's exception. + // If both failed, return the current thread's exception. local.addSuppressed(remote); exception = local; } else if (local != null) { diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/templates/TLSBase.java openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/TLSBase.java --- openjdk-21-21.0.8+9/test/jdk/javax/net/ssl/templates/TLSBase.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/net/ssl/templates/TLSBase.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -21,19 +21,16 @@ * questions. */ -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.SSLServerSocketFactory; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; +import javax.net.ssl.*; +import java.io.*; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.security.KeyStore; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.X509CertSelector; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; /** @@ -68,11 +65,11 @@ TLSBase() { String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + keyStoreFile; String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + trustStoreFile; System.setProperty("javax.net.ssl.keyStore", keyFilename); System.setProperty("javax.net.ssl.keyStorePassword", passwd); System.setProperty("javax.net.ssl.trustStore", trustFilename); @@ -80,30 +77,65 @@ } // Base read operation - byte[] read(SSLSocket sock) { - try { - BufferedReader reader = new BufferedReader( - new InputStreamReader(sock.getInputStream())); - String s = reader.readLine(); - System.err.println("(read) " + name + ": " + s); - return s.getBytes(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; + byte[] read(SSLSocket sock) throws Exception { + BufferedReader reader = new BufferedReader( + new InputStreamReader(sock.getInputStream())); + String s = reader.readLine(); + System.err.println("(read) " + name + ": " + s); + return s.getBytes(); } // Base write operation - public void write(SSLSocket sock, byte[] data) { - try { - PrintWriter out = new PrintWriter( - new OutputStreamWriter(sock.getOutputStream())); - out.println(new String(data)); - out.flush(); - System.err.println("(write)" + name + ": " + new String(data)); - } catch (Exception e) { - e.printStackTrace(); - } + public void write(SSLSocket sock, byte[] data) throws Exception { + PrintWriter out = new PrintWriter( + new OutputStreamWriter(sock.getOutputStream())); + out.println(new String(data)); + out.flush(); + System.err.println("(write)" + name + ": " + new String(data)); + } + + private static KeyManager[] getKeyManager(boolean empty) throws Exception { + FileInputStream fis = null; + if (!empty) { + fis = new FileInputStream(System.getProperty("test.src", "./") + + "/" + pathToStores + "/" + keyStoreFile); + } + // Load the keystore + char[] pwd = passwd.toCharArray(); + KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + ks.load(fis, pwd); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); + kmf.init(ks, pwd); + return kmf.getKeyManagers(); + } + + private static TrustManager[] getTrustManager(boolean empty) throws Exception { + FileInputStream fis = null; + if (!empty) { + fis = new FileInputStream(System.getProperty("test.src", "./") + + "/" + pathToStores + "/" + trustStoreFile); + } + // Load the keystore + KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + ks.load(fis, passwd.toCharArray()); + + PKIXBuilderParameters pkixParams = + new PKIXBuilderParameters(ks, new X509CertSelector()); + + // Explicitly set revocation based on the command-line + // parameters, default false + pkixParams.setRevocationEnabled(false); + + // Register the PKIXParameters with the trust manager factory + ManagerFactoryParameters trustParams = + new CertPathTrustManagerParameters(pkixParams); + + // Create the Trust Manager Factory using the PKIX variant + // and initialize it with the parameters configured above + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(trustParams); + return tmf.getTrustManagers(); } /** @@ -116,19 +148,22 @@ // Clients sockets are kept in a hash table with the port as the key. ConcurrentHashMap clientMap = new ConcurrentHashMap<>(); - boolean exit = false; Thread t; + List exceptionList = new ArrayList<>(); - Server() { + Server(ServerBuilder builder) { super(); name = "server"; try { - sslContext = SSLContext.getDefault(); + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(TLSBase.getKeyManager(builder.km), + TLSBase.getTrustManager(builder.tm), null); fac = sslContext.getServerSocketFactory(); ssock = (SSLServerSocket) fac.createServerSocket(0); + ssock.setNeedClientAuth(builder.clientauth); serverPort = ssock.getLocalPort(); } catch (Exception e) { - System.err.println(e.getMessage()); + System.err.println("Failure during server initialization"); e.printStackTrace(); } @@ -137,13 +172,15 @@ try { while (true) { System.err.println("Server ready on port " + - serverPort); + serverPort); SSLSocket c = (SSLSocket)ssock.accept(); clientMap.put(c.getPort(), c); try { write(c, read(c)); } catch (Exception e) { + System.out.println("Caught " + e.getMessage()); e.printStackTrace(); + exceptionList.add(e); } } } catch (Exception ex) { @@ -154,11 +191,59 @@ t.start(); } + Server() { + this(new ServerBuilder()); + } + + /** + * @param km - true for an empty key manager + * @param tm - true for an empty trust manager + */ + Server(boolean km, boolean tm) { + super(); + name = "server"; + try { + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(TLSBase.getKeyManager(km), + TLSBase.getTrustManager(tm), null); + fac = sslContext.getServerSocketFactory(); + ssock = (SSLServerSocket) fac.createServerSocket(0); + ssock.setNeedClientAuth(true); + serverPort = ssock.getLocalPort(); + } catch (Exception e) { + System.err.println("Failure during server initialization"); + e.printStackTrace(); + } + + // Thread to allow multiple clients to connect + t = new Thread(() -> { + try { + while (true) { + System.err.println("Server ready on port " + + serverPort); + SSLSocket c = (SSLSocket)ssock.accept(); + clientMap.put(c.getPort(), c); + try { + write(c, read(c)); + } catch (Exception e) { + System.out.println("Caught " + e.getMessage()); + e.printStackTrace(); + exceptionList.add(e); + } + } + } catch (Exception ex) { + System.err.println("Server Down"); + ex.printStackTrace(); + } + }); + t.start(); + } + // Exit test to quit the test. This must be called at the end of the // test or the test will never end. void done() { try { - t.interrupt(); + t.join(5000); ssock.close(); } catch (Exception e) { System.err.println(e.getMessage()); @@ -167,7 +252,7 @@ } // Read from the client - byte[] read(Client client) { + byte[] read(Client client) throws Exception { SSLSocket s = clientMap.get(Integer.valueOf(client.getPort())); if (s == null) { System.err.println("No socket found, port " + client.getPort()); @@ -176,13 +261,13 @@ } // Write to the client - void write(Client client, byte[] data) { + void write(Client client, byte[] data) throws Exception { write(clientMap.get(client.getPort()), data); } // Server writes to the client, then reads from the client. // Return true if the read & write data match, false if not. - boolean writeRead(Client client, String s) { + boolean writeRead(Client client, String s) throws Exception{ write(client, s.getBytes()); return (Arrays.compare(s.getBytes(), client.read()) == 0); } @@ -198,30 +283,61 @@ SSLSocket s = clientMap.get(Integer.valueOf(c.getPort())); s.close(); } + + List getExceptionList() { + return exceptionList; + } } + static class ServerBuilder { + boolean km = false, tm = false, clientauth = false; + + ServerBuilder setKM(boolean b) { + km = b; + return this; + } + + ServerBuilder setTM(boolean b) { + tm = b; + return this; + } + + ServerBuilder setClientAuth(boolean b) { + clientauth = b; + return this; + } + + Server build() { + return new Server(this); + } + } /** * Client side will establish a connection from the constructor and wait. * It must be run after the Server constructor is called. */ static class Client extends TLSBase { SSLSocket sock; - + boolean km, tm; Client() { + this(false, false); + } + + /** + * @param km - true sets an empty key manager + * @param tm - true sets an empty trust manager + */ + Client(boolean km, boolean tm) { super(); - try { - sslContext = SSLContext.getDefault(); - } catch (Exception e) { - System.err.println(e.getMessage()); - e.printStackTrace(); - } + this.km = km; + this.tm = tm; connect(); } // Connect to server. Maybe runnable in the future public SSLSocket connect() { try { - sslContext = SSLContext.getDefault(); + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(TLSBase.getKeyManager(km), TLSBase.getTrustManager(tm), null); sock = (SSLSocket)sslContext.getSocketFactory().createSocket(); sock.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), serverPort)); System.err.println("Client connected using port " + @@ -236,21 +352,21 @@ } // Read from the client socket - byte[] read() { + byte[] read() throws Exception { return read(sock); } // Write to the client socket - void write(byte[] data) { + void write(byte[] data) throws Exception { write(sock, data); } - void write(String s) { + void write(String s) throws Exception { write(sock, s.getBytes()); } // Client writes to the server, then reads from the server. // Return true if the read & write data match, false if not. - boolean writeRead(Server server, String s) { + boolean writeRead(Server server, String s) throws Exception { write(s.getBytes()); return (Arrays.compare(s.getBytes(), server.read(this)) == 0); } diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/sound/midi/File/SMFInterruptedRunningStatus.java openjdk-21-21.0.9+10/test/jdk/javax/sound/midi/File/SMFInterruptedRunningStatus.java --- openjdk-21-21.0.8+9/test/jdk/javax/sound/midi/File/SMFInterruptedRunningStatus.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/sound/midi/File/SMFInterruptedRunningStatus.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2023, 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.io.ByteArrayInputStream; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.Track; + +/** + * @test + * @bug 8319598 + * @summary SMFParser bug with running status, interrupted by Meta or SysEx messages + */ +public class SMFInterruptedRunningStatus { + + public static void main(String[] args) throws Exception { + + byte[][] files = new byte[][] {SMF_1, SMF_2, SMF_3}; + for (int i = 0; i < files.length; i++) { + Sequence seq = MidiSystem.getSequence( + new ByteArrayInputStream(files[i])); + testSequence(seq, i + 1); + } + + // no exception thrown, all files have been parsed correctly + System.out.println("Test passed"); + } + + private static void testSequence(Sequence seq, int fileNumber) { + + // check number of tracks and number of events + Track[] tracks = seq.getTracks(); + if (1 != tracks.length) { + throw new RuntimeException("file number " + + fileNumber + " fails (incorrect number of tracks: " + + tracks.length + ")"); + } + Track track = tracks[0]; + if (7 != track.size()) { + throw new RuntimeException("file number " + fileNumber + + " fails (incorrect number of events: " + + track.size() + ")"); + } + + // check status byte of each message + int[] expectedStatusBytes = new int[] { + 0x90, 0xFF, 0x90, 0x90, 0x90, 0xFF, 0xFF}; + for (int i = 0; i < expectedStatusBytes.length; i++) { + int expected = expectedStatusBytes[i]; + if (expected != track.get(i).getMessage().getStatus()) { + throw new RuntimeException("file number " + fileNumber + + " fails (wrong status byte in event " + i + ")"); + } + } + } + + // MIDI file without running status - should work equally before + // and after the bugfix + private static final byte[] SMF_1 = { + 0x4D, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, // file header (start) + 0x00, 0x01, 0x00, 0x01, 0x00, (byte) 0x80, // file header (end) + 0x4D, 0x54, 0x72, 0x6B, 0x00, 0x00, 0x00, 0x24, // track header + 0x00, // delta time + (byte) 0x90, 0x3C, 0x7F, // Note-ON (C) + 0x40, // delta time + (byte) 0xFF, 0x01, 0x04, 0x54, 0x65, 0x73, 0x74, // META (text) + 0x20, // delta time + (byte) 0x90, 0x3C, 0x00, // Note-OFF (C) + 0x20, // delta time + (byte) 0x90, 0x3E, 0x7F, // Note-ON (D) + 0x60, // delta time + (byte) 0x90, 0x3E, 0x00, // Note-OFF (D) + 0x20, // delta time + (byte) 0xFF, 0x01, 0x04, 0x54, 0x65, 0x73, 0x74, // META (text) + 0x00, // delta time + (byte) 0xFF, 0x2F, 0x00 // META (end of track) + }; + + // MIDI file with running status, interrupted by a META message + // - failed before the bugfix + private static final byte[] SMF_2 = { + 0x4D, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, // file header (start) + 0x00, 0x01, 0x00, 0x01, 0x00, (byte) 0x80, // file header (end) + 0x4D, 0x54, 0x72, 0x6B, 0x00, 0x00, 0x00, 0x21, // track header + 0x00, // delta time + (byte) 0x90, 0x3C, 0x7F, // Note-ON (C) + 0x40, // delta time + (byte) 0xFF, 0x01, 0x04, 0x54, 0x65, 0x73, 0x74, // META (interruptor) + 0x20, // delta time + 0x3C, 0x00, // Note-OFF (C) - running status + 0x20, // delta time + 0x3E, 0x7F, // Note-ON (D) - running status + 0x60, // delta time + 0x3E, 0x00, // Note-OFF (D) - running status + 0x20, // delta time + (byte) 0xFF, 0x01, 0x04, 0x54, 0x65, 0x73, 0x74, // META (text) + 0x00, // delta time + (byte) 0xFF, 0x2F, 0x00 // META (end of track) + }; + + // MIDI file with running status, interrupted by a META message + // - succeeded before the bugfix but with wrong interpretation of the data + private static final byte[] SMF_3 = { + 0x4D, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, // file header (start) + 0x00, 0x01, 0x00, 0x01, 0x00, (byte) 0x80, // file header (end) + 0x4D, 0x54, 0x72, 0x6B, 0x00, 0x00, 0x00, 0x21, // track header + 0x00, // delta time + (byte) 0x90, 0x3C, 0x7F, // Note-ON (C) + 0x40, // delta time + (byte) 0xFF, 0x01, 0x04, 0x54, 0x65, 0x73, 0x74, // META (interruptor) + 0x20, // delta time + 0x3C, 0x00, // Note-OFF (C) - running status + 0x0D, // delta time + 0x3E, 0x7F, // Note-ON (D) - running status + 0x60, // delta time + 0x3E, 0x00, // Note-OFF (D) - running status + 0x20, // delta time + (byte) 0xFF, 0x01, 0x04, 0x54, 0x65, 0x73, 0x74, // META (text) + 0x00, // delta time + (byte) 0xFF, 0x2F, 0x00 // META (end of track) + }; +} + diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JColorChooser/Test6977726.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JColorChooser/Test6977726.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JColorChooser/Test6977726.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JColorChooser/Test6977726.java 2025-10-13 07:49:24.000000000 +0000 @@ -41,7 +41,14 @@ String instructions = """ Check that there is a panel with "Text Preview Panel" text and with title "Preview" in the JColorChooser. - Test passes if the panel is as described, test fails otherwise."""; + Test passes if the panel is as described, test fails otherwise. + + Note: "Preview" title is not applicable for GTK Look and Feel."""; + + // In case this test is run with GTK L&F, the preview panel title + // is missing due to the "ColorChooser.showPreviewPanelText" property + // which is set to "Boolean.FALSE" for GTK L&F. Test instructions are + // modified to reflect that "Preview" title is not applicable for GTK L&F. PassFailJFrame.builder() .title("Test6977726") diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JComboBox/6559152/bug6559152.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JComboBox/6559152/bug6559152.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JComboBox/6559152/bug6559152.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JComboBox/6559152/bug6559152.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -48,8 +48,8 @@ private static JFrame frame; private static JComboBox cb; private static Robot robot; - private static Point p = null; - private static Dimension d; + private static volatile Point p = null; + private static volatile Dimension d; public static void main(String[] args) throws Exception { robot = new Robot(); @@ -84,7 +84,7 @@ } private static void setupUI() { - frame = new JFrame(); + frame = new JFrame("bug6559152"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); DefaultTableModel model = new DefaultTableModel(1, 1); diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ - - - - - -The test is suitable only for Windows - -1. Create a link -2. Copy path to the link into TextField -3. Run the Windows Task Manager. Select the Processes tab and find the java process -4. Press the Start button in the test window -5. Wait several minutes and observe in the Windows Task Manager -that Memory Usage of java process is not increasing - - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -21,54 +21,82 @@ * questions. */ -/* @test %W% %E% - @bug 6798062 - @summary Memory Leak on using getFiles of FileSystemView - @author Pavel Porvatov - @modules java.desktop/sun.awt - java.desktop/sun.awt.shell - @run applet/manual=done bug6798062.html -*/ +/* + * @test + * @bug 6798062 + * @requires (os.family == "windows") + * @summary Memory Leak on using getFiles of FileSystemView + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @modules java.desktop/sun.awt + * java.desktop/sun.awt.shell + * @run main/manual bug6798062 + */ import sun.awt.OSInfo; import sun.awt.shell.ShellFolder; -import javax.swing.*; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.*; import java.io.File; import java.io.FileNotFoundException; - -public class bug6798062 extends JApplet { - - private final JSlider slider = new JSlider(0, 100); - - private final JTextField tfLink = new JTextField(); - - private final JButton btnStart = new JButton("Start"); - - private final JButton btnStop = new JButton("Stop"); - - private final JButton btnGC = new JButton("Run System.gc()"); +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.JTextField; + +public class bug6798062 { + + private static final String INSTRUCTIONS = """ + The test is suitable only for Windows. + + 1. Create a shortcut (.lnk) file + 2. Copy path to the shortcut (.lnk file) into TextField + 3. Run the Windows Task Manager. Select the Processes tab and find the java process + 4. Press the Start button in the test window + 5. Wait several minutes and observe in the Windows Task Manager + that Memory Usage of java process is not increasing + If memory usage is increasing, click Fail else click Pass."""; + + private static JSlider slider; + private static JTextField tfLink; + private static JButton btnStart; + private static JButton btnStop; + private static JButton btnGC; private ShellFolder folder; - private Thread thread; - public static void main(String[] args) { + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JFileChooser Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(10) + .rows(10) + .columns(35) + .testUI(bug6798062::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + slider = new JSlider(0, 100); + tfLink = new JTextField(); + btnStart = new JButton("Start"); + btnStop = new JButton("Stop"); + btnGC = new JButton("Run System.gc()"); JFrame frame = new JFrame("bug6798062"); frame.setSize(400, 300); - frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new bug6798062().initialize()); - frame.setVisible(true); - } - - public void init() { - add(initialize()); + return frame; } private JComponent initialize() { @@ -87,7 +115,7 @@ try { folder = ShellFolder.getShellFolder(new File(tempDir)); } catch (FileNotFoundException e) { - fail("Directory " + tempDir + " not found"); + fail("Directory not found"); } slider.setMajorTickSpacing(10); @@ -153,7 +181,7 @@ } private static void fail(String msg) { - throw new RuntimeException(msg); + PassFailJFrame.forceFail(msg); } private class MyThread extends Thread { @@ -169,7 +197,7 @@ try { linkFolder = ShellFolder.getShellFolder(new File(link)); } catch (FileNotFoundException e) { - e.printStackTrace(); + fail("File not found"); linkFolder = null; } @@ -184,7 +212,7 @@ try { link.getLinkLocation(); } catch (FileNotFoundException e) { - e.printStackTrace(); + fail("File not found"); } } diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ - - - - - - - -Follow the instructions below. -1) Check that current filter in the opened JFileChooser is a "CustomFileFilter". -2) Close the JFileChooser. -3) Test will repeat steps 1 - 2 for all supported look and feels. -4) If it's true for all look and feels then the test passed, otherwise it failed. - - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -21,44 +21,57 @@ * questions. */ -import java.applet.Applet; import java.io.File; - +import java.awt.BorderLayout; import javax.swing.JFileChooser; +import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.filechooser.FileFilter; -public final class FileFilterDescription extends Applet { - - @Override - public void init() { - } - - @Override - public void start() { - try { - test(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } +/* + * @test + * @bug 8029536 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileFilterDescription + */ +public final class FileFilterDescription { + private static final String INSTRUCTIONS = """ + 1) Check that current filter in the opened JFileChooser is a "CustomFileFilter". + 2) Close the JFileChooser. + 3) Test will repeat steps 1 - 2 for all supported look and feels. + 4) If it's true for all look and feels then click Pass else click Fail. """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("JFileChooser Filefilter Instructions") + .instructions(INSTRUCTIONS) + .rows(10) + .columns(35) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .build(); - public static void test() throws Exception { final UIManager.LookAndFeelInfo[] infos = UIManager .getInstalledLookAndFeels(); for (final UIManager.LookAndFeelInfo info : infos) { SwingUtilities.invokeAndWait(() -> { - final JFileChooser chooser = new JFileChooser(); setLookAndFeel(info); + JFrame frame = new JFrame("JFileChooser FileFilter test"); + final JFileChooser chooser = new JFileChooser(); chooser.setAcceptAllFileFilterUsed(false); chooser.setFileFilter(new CustomFileFilter()); SwingUtilities.updateComponentTreeUI(chooser); + frame.add(chooser, BorderLayout.CENTER); + frame.pack(); + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, PassFailJFrame.Position.TOP_LEFT_CORNER); chooser.showDialog(null, "Open"); }); } + passFailJFrame.awaitAndCheck(); } private static void setLookAndFeel(final UIManager.LookAndFeelInfo info) { diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ - - - - - -Drag the internal frame inside the green undecorated window, -if you can drag it the test passes, otherwise fails. - - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -21,11 +21,14 @@ * questions. */ -/* @test - @bug 6726866 8186617 - @summary Repainting artifacts when resizing or dragging JInternalFrames in +/* + * @test + * @bug 6726866 8186617 + * @summary Repainting artifacts when resizing or dragging JInternalFrames in non-opaque toplevel - @run applet/manual=yesno bug6726866.html + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug6726866 */ import java.awt.Color; @@ -36,10 +39,26 @@ import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +public class bug6726866 { -public class bug6726866 extends JApplet { + private static final String INSTRUCTIONS = """ + Drag the internal frame inside the green undecorated window, + if you can drag it the test passes, otherwise fails. """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JInternalFrame Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(bug6726866::createUI) + .build() + .awaitAndCheck(); + } - public void init() { + private static JFrame createUI() { JFrame frame = new JFrame("bug6726866"); frame.setUndecorated(true); setWindowNonOpaque(frame); @@ -53,10 +72,8 @@ desktop.add(iFrame); frame.add(desktop); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 400); - frame.setVisible(true); - frame.toFront(); + return frame; } public static void setWindowNonOpaque(Window window) { diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JMenu/bug4187996.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug4187996.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JMenu/bug4187996.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug4187996.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2001, 2025, 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 4187996 + * @summary Tests that Metal submenus overlap menu + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4187996 + */ + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.UIManager; + +public class bug4187996 { + + private static final String INSTRUCTIONS = """ + Open the menu "Menu", then "Submenu". + The submenu should be top-aligned with the menu, + and slightly overlap it horizontally. Otherwise test fails."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("bug4187996 Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug4187996::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4187996"); + JMenu submenu = new JMenu("Submenu"); + submenu.add(new JMenuItem("Sub 1")); + submenu.add(new JMenuItem("Sub 2")); + + JMenu menu = new JMenu("Menu"); + menu.add(submenu); + menu.add(new JMenuItem("Item 1")); + menu.add(new JMenuItem("Item 2")); + + JMenuBar mbar = new JMenuBar(); + mbar.add(menu); + frame.setJMenuBar(mbar); + frame.setSize(300, 100); + return frame; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JMenu/bug6471949.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug6471949.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JMenu/bug6471949.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug6471949.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011, 2025, 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 6471949 + * @summary JMenu should stay selected after escape is pressed + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug6471949 +*/ + +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug6471949 { + + private static final String INSTRUCTIONS = """ + Test the menu and its submenus for different LaF: + + Click on "Menu" and then click on "Inner" submenu + and then click on "One more" submenu. + + For Metal, Nimbus and Aqua Laf the Escape key hides the last open submenu, + Press Esc till the last menu "Inner" is closed. + If the last menu is closed then the menu button (in menubar) gets unselected. + + For Windows Laf the Escape key hides the last open submenu + if the last menu is closed then the menu button remains selected, + until the Escape key is pressed again or any other key letter pressed. + + For GTK and Motif menu, all open submenus must hide when the Escape key is pressed. + + If everything works as described, the test passes and fails otherwise."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug6471949 Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug6471949::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + + PassFailJFrame.log("Menu.cancelMode = " + + UIManager.getString("Menu.cancelMode")); + PassFailJFrame.log("Menu.preserveTopLevelSelection = " + + UIManager.getBoolean("Menu.preserveTopLevelSelection")); + PassFailJFrame.log(""); + + JFrame frame = new JFrame("bug6471949"); + JMenuBar bar = new JMenuBar(); + JMenu menu = new JMenu("Menu"); + menu.setMnemonic('m'); + + JMenuItem item = new JMenuItem("Item"); + menu.add(item); + JMenu inner = new JMenu("Inner"); + inner.add(new JMenuItem("Test")); + JMenu oneMore = new JMenu("One more"); + oneMore.add(new JMenuItem("Lala")); + inner.add(oneMore); + menu.add(inner); + + JMenu lafMenu = new JMenu("Change LaF"); + + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + for (final UIManager.LookAndFeelInfo lafInfo : lafs) { + JMenuItem lafItem = new JMenuItem(lafInfo.getName()); + lafItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + setLaf(frame, lafInfo.getClassName()); + } + }); + lafMenu.add(lafItem); + } + + frame.setJMenuBar(bar); + bar.add(menu); + bar.add(lafMenu); + + JTextArea field = new JTextArea(); + frame.add(field); + field.requestFocusInWindow(); + frame.pack(); + return frame; + } + + private static void setLaf(JFrame frame, String laf) { + try { + UIManager.setLookAndFeel(laf); + SwingUtilities.updateComponentTreeUI(frame); + PassFailJFrame.log("Menu.cancelMode = " + + UIManager.getString("Menu.cancelMode")); + PassFailJFrame.log("Menu.preserveTopLevelSelection = " + + UIManager.getBoolean("Menu.preserveTopLevelSelection")); + PassFailJFrame.log(""); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JMenu/bug6513492.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug6513492.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JMenu/bug6513492.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenu/bug6513492.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2011, 2025, 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 6513492 +* @summary Escape key needs to be pressed twice to remove focus from an empty/diabled Menu. +* @library /java/awt/regtesthelpers +* @build PassFailJFrame +* @run main/manual bug6513492 +*/ + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class bug6513492 { + + private static final String INSTRUCTIONS = """ + Test Menu for different LaF: + + * For Windows Laf: + Click the editor + Click EmpyMenu, press Escape -> focus must go to the editor + Click EmpyMenu, press right arrow button, press Escape -> focus must go to the editor + Click SubMenuTest, highlight the first disabled submenu, press Escape + -> focus must stay at the topLevelMenu + + * For Metal, Nimbus and Aqua Laf + Click the editor + Click SubMenuTest, highlight the EmptySubmenu, press Escape -> focus must go to the editor + Click SubMenuTest, highlight the EnabledItem, press Escape -> focus must go to the editor + + * For GTK and Motif + Click the editor + Open any menu or submenu, press Escape -> focus must go to the editor."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug6513492 Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(bug6513492::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + PassFailJFrame.log("Menu.cancelMode = " + + UIManager.getString("Menu.cancelMode")); + PassFailJFrame.log("Menu.preserveTopLevelSelection = " + + UIManager.getBoolean("Menu.preserveTopLevelSelection")); + PassFailJFrame.log(""); + + JFrame frame = new JFrame("bug6513492"); + JMenuBar bar = new JMenuBar(); + bar.add(new JMenu("EmptyMenu")); + + JMenu disabledMenu = new JMenu("NotEmpyButDisabled"); + disabledMenu.add(new JMenuItem("item")); + disabledMenu.setEnabled(false); + bar.add(disabledMenu); + + JMenu menu = new JMenu("SubMenuTest"); + JMenu disabledSubmenu = new JMenu("Submenu"); + disabledSubmenu.add(new JMenuItem("item")); + disabledSubmenu.setEnabled(false); + menu.add(disabledSubmenu); + + JMenu enabledSubmenu = new JMenu("Submenu"); + enabledSubmenu.add(new JMenuItem("item")); + menu.add(enabledSubmenu); + + JMenu emptySubmenu = new JMenu("EmptySubmenu"); + menu.add(emptySubmenu); + + menu.add(new JMenuItem("EnabledItem")); + JMenuItem item = new JMenuItem("DisabledItem"); + item.setEnabled(false); + menu.add(item); + bar.add(menu); + + JMenu lafMenu = new JMenu("Change LaF"); + + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + for (final UIManager.LookAndFeelInfo lafInfo : lafs) { + JMenuItem lafItem = new JMenuItem(lafInfo.getName()); + lafItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + setLaf(frame, lafInfo.getClassName()); + } + }); + lafMenu.add(lafItem); + } + + frame.setJMenuBar(bar); + bar.add(menu); + bar.add(lafMenu); + + JTextArea field = new JTextArea("The editor"); + frame.add(field); + field.requestFocusInWindow(); + frame.pack(); + return frame; + } + + private static void setLaf(JFrame frame, String laf) { + try { + UIManager.setLookAndFeel(laf); + SwingUtilities.updateComponentTreeUI(frame); + PassFailJFrame.log("Menu.cancelMode = " + + UIManager.getString("Menu.cancelMode")); + PassFailJFrame.log("Menu.preserveTopLevelSelection = " + + UIManager.getBoolean("Menu.preserveTopLevelSelection")); + PassFailJFrame.log(""); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025, 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 8348760 + * @summary Verify if RadioButtonMenuItem bullet and + * JCheckboxMenuItem checkmark is shown if + * JRadioButtonMenuItem and JCheckboxMenuItem + * is rendered with ImageIcon in WindowsLookAndFeel + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestRadioAndCheckMenuItemWithIcon + */ + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; + +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.KeyStroke; +import javax.swing.UIManager; + +public class TestRadioAndCheckMenuItemWithIcon { + + private static final String INSTRUCTIONS = """ + A top level Menu will be shown. + + Clicking on the Menu will show a + JRadioButtonMenuItem group with 3 radiobutton menuitems + and a JCheckBoxMenuItem group with 3 checkbox menuitems. + + First radiobutton menuitem is selected with imageicon of a red square. + Second radiobutton menuitem is unselected with imageicon. + Third radiobutton menuItem is unselected without imageicon. + + First checkbox menuitem is selected with imageicon. + Second checkbox menuitem is unselected with imageicon. + Third checkbox menuItem is unselected without imageicon. + + Verify that for first JRadioButtonMenuItem with imageicon, + a bullet is shown alongside the imageicon and + for first JCheckBoxMenuItem with imageicon + a checkmark is shown alongside the imageicon. + + If bullet and checkmark is shown, test passes else fails."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + PassFailJFrame.builder() + .title("JRadioButtonMenuItem Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(TestRadioAndCheckMenuItemWithIcon::doTest) + .build() + .awaitAndCheck(); + } + + public static JFrame doTest() { + BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); + Graphics g = img.getGraphics(); + g.setColor(Color.red); + g.fillRect(0, 0, img.getWidth(), img.getHeight()); + g.dispose(); + + BufferedImage img2 = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB); + Graphics g2 = img2.getGraphics(); + g2.setColor(Color.red); + g2.fillRect(0, 0, img2.getWidth(), img2.getHeight()); + g2.dispose(); + + JFrame frame = new JFrame("RadioButtonWithImageIcon"); + ImageIcon imageIcon1 = new ImageIcon(img); + ImageIcon imageIcon2 = new ImageIcon(img2); + AbstractButton button1; + JRadioButtonMenuItem m1 = new JRadioButtonMenuItem("JRadioButtonMenuItem 1", + imageIcon1); + m1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, ActionEvent.ALT_MASK|ActionEvent.CTRL_MASK|ActionEvent.SHIFT_MASK)); + button1 = m1; + button1.setSelected(true); + AbstractButton button2 = new JRadioButtonMenuItem("JRadioButtonMenuItem 2", imageIcon2); + AbstractButton button3 = new JRadioButtonMenuItem("JRadioButtonMenuItem 3"); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(button1); + buttonGroup.add(button2); + buttonGroup.add(button3); + + AbstractButton check1 = new JCheckBoxMenuItem("JCheckBoxMenuItem 1", + imageIcon1); + check1.setSelected(true); + AbstractButton check2 = new JCheckBoxMenuItem("JCheckBoxMenuItem 2", imageIcon1); + JCheckBoxMenuItem c3; + AbstractButton check3 = c3 = new JCheckBoxMenuItem("JCheckBoxMenuItem 3"); + c3.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, ActionEvent.ALT_MASK|ActionEvent.CTRL_MASK|ActionEvent.SHIFT_MASK)); + + JMenu topLevel = new JMenu("Menu"); + + topLevel.add(button1); + topLevel.add(button2); + topLevel.add(button3); + + topLevel.addSeparator(); + + topLevel.add(check1); + topLevel.add(check2); + topLevel.add(check3); + + AbstractButton menuitem1 = new JMenuItem("MenuItem1"); + AbstractButton menuitem2 = new JMenuItem("MenuItem2", imageIcon1); + topLevel.addSeparator(); + topLevel.add(menuitem1); + topLevel.add(menuitem2); + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(topLevel); + + frame.setJMenuBar(menuBar); + frame.setSize(300, 300); + return frame; + + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ - - - - - Message Dialog should pop up - with a button font size 10 - and message font size 24. - - It should be true even on OS X. - If it is not so press "Fail" else press "Pass". - - - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2001, 2015, 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 4174551 - * @summary JOptionPane should allow custom buttons - * @author Xhipra Tyagi(xhipra.tyagi@india.sun.com) area=Swing - * @run applet/manual=yesno bug4174551.html - */ -import java.awt.Font; -import javax.swing.JApplet; -import javax.swing.UIManager; -import javax.swing.JOptionPane; - -public class bug4174551 extends JApplet { - - public void init() { - try { - java.awt.EventQueue.invokeLater( () -> { - UIManager.getDefaults().put("OptionPane.buttonFont", new Font("Dialog", Font.PLAIN, 10)); - UIManager.getDefaults().put("OptionPane.messageFont", new Font("Dialog", Font.PLAIN, 24)); - JOptionPane.showMessageDialog(null, "HI 24!"); - - System.out.println(UIManager.getDefaults().get("OptionPane.buttonFont")); - System.out.println(UIManager.getDefaults().get("OptionPane.messageFont")); - }); - }catch(Exception ex) { - ex.printStackTrace(); - } - } -} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ - - - - - High resolution icon test, bug ID 8024926 - - - -

See the dialog box (usually in upper left corner) for instructions

- - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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.Dialog; -import java.awt.EventQueue; -import java.awt.Frame; -import java.awt.TextArea; -import javax.swing.JApplet; -import javax.swing.JOptionPane; - -import jdk.test.lib.Platform; - -/** - * @test - * @bug 8024926 8040279 - * @summary [macosx] AquaIcon HiDPI support - * @author Alexander Scherbatiy - * @library /test/lib - * @build jdk.test.lib.Platform - * @run applet/manual=yesno bug8024926.html - */ -public class bug8024926 extends JApplet { - //Declare things used in the test, like buttons and labels here - - public void init() { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout(new BorderLayout()); - - - if (Platform.isOSX()) { - String[] instructions = { - "Verify that high resolution system icons are used" - + " in JOptionPane on HiDPI displays.", - "1) Run the test on Retina display or enable the Quartz Debug" - + " and select the screen resolution with (HiDPI) label", - "2) Check that the error icon on the JOptionPane is smooth", - "If so, press PASS, else press FAIL." - }; - Sysout.createDialogWithInstructions(instructions); - - } else { - String[] instructions = { - "This test is not applicable to the current platform. Press PASS." - }; - Sysout.createDialogWithInstructions(instructions); - } - - - }//End init() - - public void start() { - //Get things going. Request focus, set size, et cetera - setSize(200, 200); - setVisible(true); - validate(); - EventQueue.invokeLater(new Runnable() { - - public void run() { - createAndShowGUI(); - } - }); - }// start() - - //The rest of this class is the actions which perform the test... - //Use Sysout.println to communicate with the user NOT System.out!! - //Sysout.println ("Something Happened!"); - private static void createAndShowGUI() { - JOptionPane.showMessageDialog(null, - "Icons should have high resolution.", - "High resolution icon test.", - JOptionPane.ERROR_MESSAGE); - } -}// class BlockedWindowTest - -/* Place other classes related to the test after this line */ -/** - * ************************************************** - * Standard Test Machinery DO NOT modify anything below -- it's a standard chunk - * of code whose purpose is to make user interaction uniform, and thereby make - * it simpler to read and understand someone else's test. - * ************************************************** - */ -/** - * This is part of the standard test machinery. It creates a dialog (with the - * instructions), and is the interface for sending text messages to the user. To - * print the instructions, send an array of strings to Sysout.createDialog - * WithInstructions method. Put one line of instructions per array entry. To - * display a message for the tester to see, simply call Sysout.println with the - * string to be displayed. This mimics System.out.println but works within the - * test harness as well as standalone. - */ -class Sysout { - - private static TestDialog dialog; - - public static void createDialogWithInstructions(String[] instructions) { - dialog = new TestDialog(new Frame(), "Instructions"); - dialog.printInstructions(instructions); - dialog.setVisible(true); - println("Any messages for the tester will display here."); - } - - public static void createDialog() { - dialog = new TestDialog(new Frame(), "Instructions"); - String[] defInstr = {"Instructions will appear here. ", ""}; - dialog.printInstructions(defInstr); - dialog.setVisible(true); - println("Any messages for the tester will display here."); - } - - public static void printInstructions(String[] instructions) { - dialog.printInstructions(instructions); - } - - public static void println(String messageIn) { - dialog.displayMessage(messageIn); - } -}// Sysout class - -/** - * This is part of the standard test machinery. It provides a place for the test - * instructions to be displayed, and a place for interactive messages to the - * user to be displayed. To have the test instructions displayed, see Sysout. To - * have a message to the user be displayed, see Sysout. Do not call anything in - * this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog(Frame frame, String name) { - super(frame, name); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); - add("North", instructionsText); - - messageText = new TextArea("", 5, maxStringLength, scrollBoth); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions(String[] instructions) { - //Clear out any current instructions - instructionsText.setText(""); - - //Go down array of instruction strings - - String printStr, remainingStr; - for (int i = 0; i < instructions.length; i++) { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i]; - while (remainingStr.length() > 0) { - //if longer than max then chop off first max chars to print - if (remainingStr.length() >= maxStringLength) { - //Try to chop on a word boundary - int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1); - - if (posOfSpace <= 0) { - posOfSpace = maxStringLength - 1; - } - - printStr = remainingStr.substring(0, posOfSpace + 1); - remainingStr = remainingStr.substring(posOfSpace + 1); - } //else just print - else { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append(printStr + "\n"); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage(String messageIn) { - messageText.append(messageIn + "\n"); - System.out.println(messageIn); - } -}// TestDialog class diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/bug4174551.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/bug4174551.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/bug4174551.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/bug4174551.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * 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 4174551 + * @summary JOptionPane should allow custom buttons + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4174551 + */ +import java.awt.FlowLayout; +import java.awt.Font; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.UIManager; + +public class bug4174551 { + private static final String INSTRUCTIONS = """ + Two Message Dialog should pop up side-by-side + one with a custom message font size 24 with message "HI 24" + and another with default optionpane message font size with message "HI default" + If custom message font size is not more than default message fontsize + AND + custom message buttonfont size is more than default message buttonfont size + press "Fail" else press "Pass". """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JOptionPane Instructions") + .instructions(INSTRUCTIONS) + .rows(8) + .columns(40) + .testUI(bug4174551::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JDialog createTestUI() { + JOptionPane defaultPane = new JOptionPane(); + defaultPane.setMessage("HI default"); + defaultPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); + UIManager.getDefaults().put("OptionPane.buttonFont", new Font("Dialog", Font.PLAIN, 10)); + UIManager.getDefaults().put("OptionPane.messageFont", new Font("Dialog", Font.PLAIN, 24)); + JOptionPane optionPane = new JOptionPane(); + optionPane.setMessage("HI 24!"); + optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); + JDialog dialog = new JDialog(); + dialog.setLayout(new FlowLayout()); + dialog.add(optionPane); + dialog.add(defaultPane); + dialog.pack(); + + System.out.println(UIManager.getDefaults().get("OptionPane.buttonFont")); + System.out.println(UIManager.getDefaults().get("OptionPane.messageFont")); + return dialog; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/bug8024926.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/bug8024926.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JOptionPane/bug8024926.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JOptionPane/bug8024926.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, 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.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.TextArea; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 8024926 8040279 + * @requires (os.family == "mac") + * @summary [macosx] AquaIcon HiDPI support + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug8024926 + */ +public class bug8024926 { + + private static final String INSTRUCTIONS = """ + Verify that high resolution system icons are used + in JOptionPane on HiDPI displays. + 1) Run the test on Retina display or enable the Quartz Debug + and select the screen resolution with (HiDPI) label. + "2) Check that the error icon on the JOptionPane is smooth. + "If so, press PASS, else press FAIL."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("AquaIcon HIDPI Instructions") + .instructions(INSTRUCTIONS) + .rows(10) + .columns(35) + .testUI(bug8024926::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JDialog createTestUI() { + JOptionPane optionPane = new JOptionPane("High resolution icon test"); + optionPane.setMessage("Icons should have high resolutions"); + optionPane.setMessageType(JOptionPane.ERROR_MESSAGE); + JDialog dialog = new JDialog(); + dialog.setContentPane(optionPane); + dialog.pack(); + return dialog; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ - - - - - -Click on the top-bar and combo-box more than once. -Make sure popup menu and drop-down list have a border and their items are drawn properly. - - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2013, 2014, 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 7160604 - @summary Using non-opaque windows - popups are initially not painted correctly - @author Oleg Pekhovskiy - @run applet/manual=yesno bug7160604.html -*/ - -import javax.swing.AbstractAction; -import javax.swing.BorderFactory; -import javax.swing.JApplet; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JWindow; -import javax.swing.SwingUtilities; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import static java.awt.GraphicsDevice.WindowTranslucency.*; - -public class bug7160604 extends JApplet { - - public void init() { - SwingUtilities.invokeLater(() -> { - if (!GraphicsEnvironment - .getLocalGraphicsEnvironment() - .getDefaultScreenDevice() - .isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT)) { - // Tested translucency is not supported. Test passed - return; - } - - final JWindow window = new JWindow(); - window.setLocation(200, 200); - window.setSize(300, 300); - - final JLabel label = new JLabel("...click to invoke JPopupMenu"); - label.setOpaque(true); - final JPanel contentPane = new JPanel(new BorderLayout()); - contentPane.setBorder(BorderFactory.createLineBorder(Color.RED)); - window.setContentPane(contentPane); - contentPane.add(label, BorderLayout.NORTH); - - final JComboBox comboBox = new JComboBox(new Object[]{"1", "2", "3", "4"}); - contentPane.add(comboBox, BorderLayout.SOUTH); - - final JPopupMenu jPopupMenu = new JPopupMenu(); - - jPopupMenu.add("string"); - jPopupMenu.add(new AbstractAction("action") { - @Override - public void actionPerformed(final ActionEvent e) { - } - }); - jPopupMenu.add(new JLabel("label")); - jPopupMenu.add(new JMenuItem("MenuItem")); - label.addMouseListener(new MouseAdapter() { - @Override - public void mouseReleased(final MouseEvent e) { - jPopupMenu.show(label, 0, 0); - } - }); - - window.setBackground(new Color(0, 0, 0, 0)); - - window.setVisible(true); - }); - } -} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JPopupMenu/bug7160604.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/bug7160604.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JPopupMenu/bug7160604.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JPopupMenu/bug7160604.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013, 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 7160604 + * @summary Using non-opaque windows - popups are initially not painted correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug7160604 +*/ +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GraphicsEnvironment; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import static java.awt.GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT; +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JWindow; +import javax.swing.SwingUtilities; + +public class bug7160604 { + + private static final String INSTRUCTIONS = """ + Click on the top-bar and combo-box at the bottom more than once. + Check top-bar popup menu and combo-box drop-down list have a border + and their items are drawn properly. + If yes, Click Pass else click Fail."""; + + public static void main(String[] args) throws Exception { + if (!GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT)) { + // Tested translucency is not supported. Test passed + return; + } + PassFailJFrame.builder() + .title("PopupMenu Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(bug7160604::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JWindow createTestUI() { + + final JWindow window = new JWindow(); + window.setLocation(200, 200); + window.setSize(300, 300); + + final JLabel label = new JLabel("...click to invoke JPopupMenu"); + label.setOpaque(true); + final JPanel contentPane = new JPanel(new BorderLayout()); + contentPane.setBorder(BorderFactory.createLineBorder(Color.RED)); + window.setContentPane(contentPane); + contentPane.add(label, BorderLayout.NORTH); + + final JComboBox comboBox = new JComboBox(new Object[]{"1", "2", "3", "4"}); + contentPane.add(comboBox, BorderLayout.SOUTH); + + final JPopupMenu jPopupMenu = new JPopupMenu(); + + jPopupMenu.add("string"); + jPopupMenu.add(new AbstractAction("action") { + @Override + public void actionPerformed(final ActionEvent e) { + } + }); + jPopupMenu.add(new JLabel("label")); + jPopupMenu.add(new JMenuItem("MenuItem")); + label.addMouseListener(new MouseAdapter() { + @Override + public void mouseReleased(final MouseEvent e) { + jPopupMenu.show(label, 0, 0); + } + }); + + window.setBackground(new Color(0, 0, 0, 0)); + + return window; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JRadioButton/8033699/bug8033699.java 2025-10-13 07:49:24.000000000 +0000 @@ -35,17 +35,16 @@ import java.awt.event.KeyEvent; import javax.swing.BorderFactory; -import javax.swing.BoxLayout; +import javax.swing.Box; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JFrame; -import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.SwingUtilities; import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; public class bug8033699 { - private static JFrame mainFrame; private static Robot robot; private static JButton btnStart; @@ -55,77 +54,101 @@ private static JRadioButton radioBtn2; private static JRadioButton radioBtn3; private static JRadioButton radioBtnSingle; + private static KeyboardFocusManager focusManager; public static void main(String[] args) throws Throwable { - SwingUtilities.invokeAndWait(() -> { - changeLAF(); - createAndShowGUI(); - }); - robot = new Robot(); - robot.waitForIdle(); - robot.delay(1000); - // tab key test grouped radio button - runTest1(); - robot.delay(100); - - // tab key test non-grouped radio button - runTest2(); - robot.delay(100); - - // shift tab key test grouped and non-grouped radio button - runTest3(); - robot.delay(100); - - // left/up key test in grouped radio button - runTest4(); - robot.delay(100); - - // down/right key test in grouped radio button - runTest5(); - robot.delay(100); - - // tab from radio button in group to next component in the middle of button group layout - runTest6(); - robot.delay(100); - - // tab to radio button in group from component in the middle of button group layout - runTest7(); - robot.delay(100); - - // down key circle back to first button in grouped radio button - runTest8(); - robot.delay(100); - - // Verify that ActionListener is called when a RadioButton is selected using arrow key. - runTest9(); - robot.delay(100); - - SwingUtilities.invokeAndWait(() -> mainFrame.dispose()); - } - - private static void changeLAF() { - String currentLAF = UIManager.getLookAndFeel().toString(); - System.out.println(currentLAF); - currentLAF = currentLAF.toLowerCase(); - if (currentLAF.contains("nimbus")) { - try { - UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); - } catch (Exception ex) { - ex.printStackTrace(); - } + SwingUtilities.invokeAndWait(() -> + focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager()); + + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo laf : lafs) { + testLaF(laf); + } + } + + private static void testLaF(UIManager.LookAndFeelInfo laf) throws Exception { + try { + System.out.println("Testing LaF: " + laf.getName()); + SwingUtilities.invokeAndWait(() -> { + setLookAndFeel(laf); + createAndShowGUI(); + }); + + robot.waitForIdle(); + robot.delay(1000); + + // tab key test grouped radio button + runTest1(); + robot.delay(100); + + // tab key test non-grouped radio button + runTest2(); + robot.delay(100); + + // shift tab key test grouped and non-grouped radio button + runTest3(); + robot.delay(100); + + // left/up key test in grouped radio button + runTest4(); + robot.delay(100); + + // down/right key test in grouped radio button + runTest5(); + robot.delay(100); + + // tab from radio button in group to next component in the middle of + // button group layout + runTest6(); + robot.delay(100); + + // tab to radio button in group from component in the middle of + // button group layout + runTest7(); + robot.delay(100); + + // down key circle back to first button in grouped radio button + runTest8(); + robot.delay(100); + + // Verify that ActionListener is called when a RadioButton is + // selected using arrow key + runTest9(); + robot.delay(100); + } catch (Exception e) { + Throwable cause = e.getCause(); + throw new RuntimeException("Error testing LaF: " + laf.getName() + + (cause != null ? " - " + cause.getMessage() : ""), + e); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (mainFrame != null) { + mainFrame.dispose(); + mainFrame = null; + } + }); + } + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException | + IllegalAccessException | UnsupportedLookAndFeelException e) { + System.err.println("Error setting LaF: " + laf.getName()); + throw new RuntimeException("Failed to set look and feel", e); } } private static void createAndShowGUI() { - mainFrame = new JFrame("Bug 8033699 - 8 Tests for Grouped/Non Group Radio Buttons"); + mainFrame = new JFrame("Radio Button Focus Tests"); btnStart = new JButton("Start"); btnEnd = new JButton("End"); btnMiddle = new JButton("Middle"); - JPanel box = new JPanel(); - box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS)); + Box box = Box.createVerticalBox(); box.setBorder(BorderFactory.createTitledBorder("Grouped Radio Buttons")); radioBtn1 = new JRadioButton("A"); radioBtn2 = new JRadioButton("B"); @@ -145,16 +168,17 @@ radioBtnSingle = new JRadioButton("Not Grouped"); radioBtnSingle.setSelected(true); - mainFrame.getContentPane().add(btnStart); - mainFrame.getContentPane().add(box); - mainFrame.getContentPane().add(radioBtnSingle); - mainFrame.getContentPane().add(btnEnd); + Box mainBox = Box.createVerticalBox(); + mainBox.add(btnStart); + mainBox.add(box); + mainBox.add(radioBtnSingle); + mainBox.add(btnEnd); + mainFrame.add(mainBox); mainFrame.getRootPane().setDefaultButton(btnStart); btnStart.requestFocus(); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - mainFrame.setLayout(new BoxLayout(mainFrame.getContentPane(), BoxLayout.Y_AXIS)); mainFrame.setSize(300, 300); mainFrame.setLocationRelativeTo(null); @@ -169,33 +193,41 @@ hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { - if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) { - System.out.println("Radio Button Group Go To Next Component through Tab Key failed"); - throw new RuntimeException("Focus is not on Radio Button Single as Expected"); + if (focusManager.getFocusOwner() != radioBtnSingle) { + System.out.println("Radio Button Group Go To " + + "Next Component through Tab Key failed"); + throw new RuntimeException("Focus is not on " + + "Radio Button Single as Expected"); } }); } - // Non-Grouped Radio button as a single component when traversing through tab key + // Non-Grouped Radio button as a single component when traversing through + // tab key private static void runTest2() throws Exception { hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { - if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnEnd) { - System.out.println("Non Grouped Radio Button Go To Next Component through Tab Key failed"); - throw new RuntimeException("Focus is not on Button End as Expected"); + if (focusManager.getFocusOwner() != btnEnd) { + System.out.println("Non Grouped Radio Button Go To " + + "Next Component through Tab Key failed"); + throw new RuntimeException("Focus is not on Button End " + + "as Expected"); } }); } - // Non-Grouped Radio button and Group Radio button as a single component when traversing through shift-tab key + // Non-Grouped Radio button and Group Radio button as a single component + // when traversing through shift-tab key private static void runTest3() throws Exception { hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); hitKey(KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { - if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) { - System.out.println("Radio button Group/Non Grouped Radio Button SHIFT-Tab Key Test failed"); - throw new RuntimeException("Focus is not on Radio Button A as Expected"); + if (focusManager.getFocusOwner() != radioBtn1) { + System.out.println("Radio button Group/Non Grouped " + + "Radio Button SHIFT-Tab Key Test failed"); + throw new RuntimeException("Focus is not on Radio Button A " + + "as Expected"); } }); } @@ -205,9 +237,11 @@ hitKey(KeyEvent.VK_DOWN); hitKey(KeyEvent.VK_RIGHT); SwingUtilities.invokeAndWait(() -> { - if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn3) { - System.out.println("Radio button Group UP/LEFT Arrow Key Move Focus Failed"); - throw new RuntimeException("Focus is not on Radio Button C as Expected"); + if (focusManager.getFocusOwner() != radioBtn3) { + System.out.println("Radio button Group UP/LEFT Arrow Key " + + "Move Focus Failed"); + throw new RuntimeException("Focus is not on Radio Button C " + + "as Expected"); } }); } @@ -216,9 +250,11 @@ hitKey(KeyEvent.VK_UP); hitKey(KeyEvent.VK_LEFT); SwingUtilities.invokeAndWait(() -> { - if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) { - System.out.println("Radio button Group Left/Up Arrow Key Move Focus Failed"); - throw new RuntimeException("Focus is not on Radio Button A as Expected"); + if (focusManager.getFocusOwner() != radioBtn1) { + System.out.println("Radio button Group Left/Up Arrow Key " + + "Move Focus Failed"); + throw new RuntimeException("Focus is not on Radio Button A " + + "as Expected"); } }); } @@ -227,9 +263,11 @@ hitKey(KeyEvent.VK_UP); hitKey(KeyEvent.VK_UP); SwingUtilities.invokeAndWait(() -> { - if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn2) { - System.out.println("Radio button Group Circle Back To First Button Test"); - throw new RuntimeException("Focus is not on Radio Button B as Expected"); + if (focusManager.getFocusOwner() != radioBtn2) { + System.out.println("Radio button Group Circle Back To " + + "First Button Test"); + throw new RuntimeException("Focus is not on Radio Button B " + + "as Expected"); } }); } @@ -237,9 +275,11 @@ private static void runTest7() throws Exception { hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { - if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnMiddle) { - System.out.println("Separate Component added in button group layout"); - throw new RuntimeException("Focus is not on Middle Button as Expected"); + if (focusManager.getFocusOwner() != btnMiddle) { + System.out.println("Separate Component added in" + + " button group layout"); + throw new RuntimeException("Focus is not on Middle Button" + + " as Expected"); } }); } @@ -247,18 +287,21 @@ private static void runTest8() throws Exception { hitKey(KeyEvent.VK_TAB); SwingUtilities.invokeAndWait(() -> { - if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) { - System.out.println("Separate Component added in button group layout"); - throw new RuntimeException("Focus is not on Radio Button Single as Expected"); + if (focusManager.getFocusOwner() != radioBtnSingle) { + System.out.println("Separate Component added in" + + " button group layout"); + throw new RuntimeException("Focus is not on Radio Button Single" + + " as Expected"); } }); } - private static boolean actRB1 = false; - private static boolean actRB2 = false; - private static boolean actRB3 = false; + private static volatile boolean actRB1 = false; + private static volatile boolean actRB2 = false; + private static volatile boolean actRB3 = false; - // JDK-8226892: Verify that ActionListener is called when a RadioButton is selected using arrow key. + // JDK-8226892: Verify that ActionListener is called when a RadioButton + // is selected using arrow key private static void runTest9() throws Exception { SwingUtilities.invokeAndWait(() -> { radioBtn1.setSelected(true); @@ -269,15 +312,19 @@ ActionListener actLrRB2 = e -> actRB2 = true; ActionListener actLrRB3 = e -> actRB3 = true; - radioBtn1.addActionListener(actLrRB1); - radioBtn2.addActionListener(actLrRB2); - radioBtn3.addActionListener(actLrRB3); + // Adding Action Listeners + SwingUtilities.invokeAndWait(() -> { + radioBtn1.addActionListener(actLrRB1); + radioBtn2.addActionListener(actLrRB2); + radioBtn3.addActionListener(actLrRB3); + }); hitKey(KeyEvent.VK_DOWN); hitKey(KeyEvent.VK_DOWN); hitKey(KeyEvent.VK_DOWN); - String failMessage = "ActionListener not invoked when selected using arrow key."; + String failMessage = "ActionListener not invoked when selected using " + + "arrow key."; if (!actRB2) { throw new RuntimeException("RadioButton 2: " + failMessage); } @@ -288,9 +335,12 @@ throw new RuntimeException("RadioButton 1: " + failMessage); } - radioBtn1.removeActionListener(actLrRB1); - radioBtn2.removeActionListener(actLrRB2); - radioBtn3.removeActionListener(actLrRB3); + // Removing Action Listeners + SwingUtilities.invokeAndWait(() -> { + radioBtn1.removeActionListener(actLrRB1); + radioBtn2.removeActionListener(actLrRB2); + radioBtn3.removeActionListener(actLrRB3); + }); } private static void hitKey(int keycode) { diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ - - - - -Choose the variable applet size and try to resize the applet. -The test passes the thumb is painted correctly. - - - - - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014, 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.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; - -import javax.swing.JApplet; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JScrollBar; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; - -/* - * @test - * @bug 8039464 - * @summary Tests enabling/disabling of titled border's caption - * @author Sergey Malenkov - * @run applet/manual=yesno Test8039464.html - */ - -public class Test8039464 extends JApplet { - static { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception exception) { - throw new Error("unexpected", exception); - } - } - - @Override - public void init() { - init(this); - } - - private static void init(Container container) { - container.setLayout(new GridBagLayout()); - GridBagConstraints gbc = new GridBagConstraints(); - gbc.fill = GridBagConstraints.BOTH; - gbc.gridx = 0; - gbc.gridy = 1; - JLabel label = new JLabel(); - Dimension size = new Dimension(111, 0); - label.setPreferredSize(size); - label.setMinimumSize(size); - container.add(label, gbc); - gbc.gridx = 1; - gbc.weightx = 1; - container.add(new JScrollBar(JScrollBar.HORIZONTAL, 1, 111, 1, 1111), gbc); - gbc.gridx = 2; - gbc.gridy = 0; - gbc.weightx = 0; - gbc.weighty = 1; - container.add(new JScrollBar(JScrollBar.VERTICAL, 1, 111, 1, 1111), gbc); - } - - public static void main(String[] args) throws Exception { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JFrame frame = new JFrame("8039464"); - init(frame); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame.pack(); - frame.setLocationRelativeTo(null); - frame.setVisible(true); - } - }); - } -} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JScrollBar/Test8039464.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/Test8039464.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JScrollBar/Test8039464.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JScrollBar/Test8039464.java 2025-10-13 07:49:24.000000000 +0000 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, 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.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +/* + * @test + * @bug 8039464 + * @summary Tests enabling/disabling of titled border's caption + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual Test8039464 + */ + +public class Test8039464 { + private static final String INSTRUCTIONS = """ + If the scrollbar thumb is painted correctly in system lookandfeel + click Pass else click Fail. """; + + static { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception exception) { + throw new Error("unexpected", exception); + } + } + + private static void init(Container container) { + container.setLayout(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.BOTH; + gbc.gridx = 0; + gbc.gridy = 1; + JLabel label = new JLabel(); + Dimension size = new Dimension(111, 0); + label.setPreferredSize(size); + label.setMinimumSize(size); + container.add(label, gbc); + gbc.gridx = 1; + gbc.weightx = 1; + container.add(new JScrollBar(JScrollBar.HORIZONTAL, 1, 111, 1, 1111), gbc); + gbc.gridx = 2; + gbc.gridy = 0; + gbc.weightx = 0; + gbc.weighty = 1; + container.add(new JScrollBar(JScrollBar.VERTICAL, 1, 111, 1, 1111), gbc); + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JScrollBar Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(Test8039464::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("8039464"); + init(frame); + frame.pack(); + return frame; + } +} diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JSlider/4987336/bug4987336.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/4987336/bug4987336.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JSlider/4987336/bug4987336.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/4987336/bug4987336.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ - - - - - -There are four Sliders. Each of them has a label with animated gif (a waving duke) -and a label with static image. - -Check that for every LAF animation works for all Sliders. - - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JSlider/4987336/bug4987336.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/4987336/bug4987336.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JSlider/4987336/bug4987336.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/4987336/bug4987336.java 2025-10-13 07:49:24.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -21,25 +21,58 @@ * questions. */ -/* @test - @bug 4987336 - @summary JSlider doesn't show label's animated icon. - @author Pavel Porvatov - @run applet/manual=done bug4987336.html +/* + * @test + * @bug 4987336 + * @summary JSlider doesn't show label's animated icon. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4987336 */ - -import javax.swing.*; -import javax.swing.border.TitledBorder; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import javax.swing.ButtonGroup; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JSlider; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.TitledBorder; import java.util.Hashtable; -public class bug4987336 extends JApplet { +public class bug4987336 { + private static final String INSTRUCTIONS = """ + There are four Sliders. + Each of them has a label with animated gif (a waving duke) + and a label with static image. + If it is rendered correctly, click Pass else click Fail."""; + private static final String IMAGE_RES = "box.gif"; private static final String ANIM_IMAGE_RES = "duke.gif"; + private static JFrame frame; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Slider rendering Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(bug4987336::createTestUI) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .build() + .awaitAndCheck(); + } - public void init() { + private static JFrame createTestUI() { + frame = new JFrame("bug4987336"); JPanel pnLafs = new JPanel(); pnLafs.setLayout(new BoxLayout(pnLafs, BoxLayout.Y_AXIS)); @@ -64,7 +97,9 @@ pnContent.add(createSlider(true, ANIM_IMAGE_RES, null, IMAGE_RES, IMAGE_RES)); pnContent.add(createSlider(false, ANIM_IMAGE_RES, null, IMAGE_RES, IMAGE_RES)); - getContentPane().add(new JScrollPane(pnContent)); + frame.getContentPane().add(new JScrollPane(pnContent)); + frame.pack(); + return frame; } private static JSlider createSlider(boolean enabled, @@ -99,7 +134,7 @@ return result; } - private class LafRadioButton extends JRadioButton { + private static class LafRadioButton extends JRadioButton { public LafRadioButton(final UIManager.LookAndFeelInfo lafInfo) { super(lafInfo.getName(), lafInfo.getName().equals(UIManager.getLookAndFeel().getName())); @@ -108,7 +143,7 @@ try { UIManager.setLookAndFeel(lafInfo.getClassName()); - SwingUtilities.updateComponentTreeUI(bug4987336.this); + SwingUtilities.updateComponentTreeUI(frame); } catch (Exception ex) { // Ignore such errors System.out.println("Cannot set LAF " + lafInfo.getName()); diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JSlider/6587742/bug6587742.html openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/6587742/bug6587742.html --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JSlider/6587742/bug6587742.html 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/6587742/bug6587742.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ - - - - - -Select every theme and check that all sliders looks good. -Note that every slider has a tooltip text with information about -slider configuration. -There is a small difference in sliders with property "filled = null" (it's -default behaviour when property JSlider.isFilled is not setted) -for themes: -1. OceanTheme - sliders look like filled -2. DefaultMetalTheme - sliders look like NOT filled - - diff -Nru openjdk-21-21.0.8+9/test/jdk/javax/swing/JSlider/6587742/bug6587742.java openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/6587742/bug6587742.java --- openjdk-21-21.0.8+9/test/jdk/javax/swing/JSlider/6587742/bug6587742.java 2025-07-09 05:53:39.000000000 +0000 +++ openjdk-21-21.0.9+10/test/jdk/javax/swing/JSlider/6587742/bug6587742.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2008, 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 6587742 - * @summary filling half of a JSlider's track is no longer optional - * @author Pavel Porvatov - * @run applet/manual=done bug6587742.html - */ - -import javax.swing.*; -import javax.swing.plaf.metal.DefaultMetalTheme; -import javax.swing.plaf.metal.MetalLookAndFeel; -import javax.swing.plaf.metal.MetalTheme; -import javax.swing.plaf.metal.OceanTheme; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -public class bug6587742 extends JApplet { - public void init() { - TestPanel panel = new TestPanel(); - - setContentPane(panel); - } - - private class TestPanel extends JPanel { - private final JComboBox cbThemes = new JComboBox(); - - private TestPanel() { - // Fill cbThemes - cbThemes.addItem(new OceanTheme()); - cbThemes.addItem(new DefaultMetalTheme()); - - cbThemes.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - MetalTheme theme = (MetalTheme) cbThemes.getSelectedItem(); - - if (theme != null) { - MetalLookAndFeel.setCurrentTheme(theme); - - // re-install the Metal Look and Feel - try { - UIManager.setLookAndFeel(new MetalLookAndFeel()); - } catch (UnsupportedLookAndFeelException e1) { - JOptionPane.showMessageDialog(TestPanel.this, "Can't change theme: " + e1.getMessage(), - "Error", JOptionPane.ERROR_MESSAGE); - - return; - } - - SwingUtilities.updateComponentTreeUI(bug6587742.this); - } - } - }); - - JPanel pnVertical = new JPanel(); - - pnVertical.setLayout(new BoxLayout(pnVertical, BoxLayout.Y_AXIS)); - - for (int i = 0; i < 12; i++) { - int filled = i >> 2; - - pnVertical.add(createSlider(false, filled > 1 ? null : Boolean.valueOf(filled == 1), (i & 2) == 0, - (i & 1) != 0)); - } - - JPanel pnHorizontal = new JPanel(); - - pnHorizontal.setLayout(new BoxLayout(pnHorizontal, BoxLayout.X_AXIS)); - - for (int i = 0; i < 12; i++) { - int filled = i >> 2; - - pnHorizontal.add(createSlider(true, filled > 1 ? null : Boolean.valueOf(filled == 1), (i & 2) == 0, - (i & 1) != 0)); - } - - JTabbedPane tpSliders = new JTabbedPane(); - - tpSliders.add("Vertical sliders", pnVertical); - tpSliders.add("Horizontal sliders", pnHorizontal); - - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - - add(new JLabel("Select theme:")); - add(cbThemes); - add(tpSliders); - } - } - - private static JSlider createSlider(boolean vertical, Boolean filled, boolean enabled, boolean inverted) { - JSlider result = new JSlider(vertical ? SwingConstants.VERTICAL : SwingConstants.HORIZONTAL, 0, 100, 50); - - result.setMajorTickSpacing(20); -