diff -Nru openjdk-17-17.0.3+7/debian/changelog openjdk-17-17.0.4+8/debian/changelog --- openjdk-17-17.0.3+7/debian/changelog 2022-04-24 14:03:57.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/changelog 2022-07-22 08:57:45.000000000 +0000 @@ -1,16 +1,45 @@ -openjdk-17 (17.0.3+7-0ubuntu0.20.04.1) focal-security; urgency=medium +openjdk-17 (17.0.4+8-1~20.04) focal-security; urgency=medium - * Backport 17.0.3 to Ubuntu 20.04. + * OpenJDK 17.0.4 release, build 8. + * Addresses security issues: CVE-2022-34169, CVE-2022-21541, + CVE-2022-21540, CVE-2022-21549. + + -- Matthias Klose Fri, 22 Jul 2022 10:57:45 +0200 + +openjdk-17 (17.0.4+8-1) unstable; urgency=high + + * OpenJDK 17.0.4+8 (release). + * Disable the reproducible-copyright-headers patch. + * Only try to re-run failed tests once instead of three times. + + -- Matthias Klose Wed, 20 Jul 2022 18:04:41 +0200 + +openjdk-17 (17.0.3+7-1) unstable; urgency=high + + * OpenJDK 17.0.3+7 (release). + * Security fixes + - JDK-8269938: Enhance XML processing passes redux. + - JDK-8270504, CVE-2022-21426: Better XPath expression handling. + - JDK-8272255: Completely handle MIDI files. + - JDK-8272261: Improve JFR recording file processing. + - JDK-8272588: Enhanced recording parsing. + - JDK-8272594: Better record of recordings. + - JDK-8274221: More definite BER encodings. + - JDK-8275082, JDK-8278008, CVE-2022-21476: Update XML Security for Java + to 2.3.0. + - JDK-8275151, CVE-2022-21443: Improved Object Identification. + - JDK-8277227: Better identification of OIDs. + - JDK-8277233, CVE-2022-21449: Improve ECDSA signature support. + - JDK-8277672, CVE-2022-21434: Better invocation handler handling. + - JDK-8278356: Improve file creation. + - JDK-8278449: Improve keychain support. + - JDK-8278798: Improve supported intrinsic. + - JDK-8278805: Enhance BMP image loading. + - JDK-8278972, CVE-2022-21496: Improve URL supports. + - JDK-8281388: Change wrapping of EncryptedPrivateKeyInfo. + * Refresh patches. - -- Marc Deslauriers Sun, 24 Apr 2022 10:03:57 -0400 - -openjdk-17 (17.0.3+7-0ubuntu0.22.04.1) jammy-security; urgency=medium - - * OpenJDK 17.0.3+7 build (release). - - CVE-2022-21476, CVE-2022-21496, CVE-2022-21434, CVE-2022-21426, - CVE-2022-21443, CVE-2022-21449 - - -- Marc Deslauriers Sun, 24 Apr 2022 09:50:52 -0400 + -- Matthias Klose Mon, 02 May 2022 20:04:05 +0200 openjdk-17 (17.0.2+8-1) unstable; urgency=high diff -Nru openjdk-17-17.0.3+7/debian/control openjdk-17-17.0.4+8/debian/control --- openjdk-17-17.0.3+7/debian/control 2022-04-24 14:03:57.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/control 2022-07-22 08:57:45.000000000 +0000 @@ -1,8 +1,7 @@ Source: openjdk-17 Section: java Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: OpenJDK Team +Maintainer: OpenJDK Team Uploaders: Matthias Klose Build-Depends: debhelper (>= 11), m4, lsb-release, zip, unzip, diff -Nru openjdk-17-17.0.3+7/debian/control.in openjdk-17-17.0.4+8/debian/control.in --- openjdk-17-17.0.3+7/debian/control.in 2022-04-24 14:03:57.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/control.in 2021-06-17 11:30:11.000000000 +0000 @@ -1,8 +1,7 @@ Source: @basename@ Section: java Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: OpenJDK Team +Maintainer: OpenJDK Team Uploaders: Matthias Klose Build-Depends: @bd_debhelper@ m4, lsb-release, zip, unzip, diff -Nru openjdk-17-17.0.3+7/debian/copyright openjdk-17-17.0.4+8/debian/copyright --- openjdk-17-17.0.3+7/debian/copyright 2022-01-20 16:13:28.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/copyright 2022-07-20 09:21:08.000000000 +0000 @@ -2,7 +2,7 @@ Wed, 08 Aug 2007 15:55:39 +0200. It was downloaded from - https://github.com/openjdk/jdk17u-dev + https://github.com/openjdk/jdk17u ------------------------------------------------------------------------------ Upstream Authors: diff -Nru openjdk-17-17.0.3+7/debian/patches/default-jvm-cfg.diff openjdk-17-17.0.4+8/debian/patches/default-jvm-cfg.diff --- openjdk-17-17.0.3+7/debian/patches/default-jvm-cfg.diff 2021-04-08 07:39:27.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/default-jvm-cfg.diff 2022-05-02 18:22:39.000000000 +0000 @@ -1,6 +1,6 @@ --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c -@@ -2077,7 +2077,7 @@ jint +@@ -2079,7 +2079,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; -@@ -2092,6 +2092,11 @@ ReadKnownVMs(const char *jvmCfgName, jbo +@@ -2094,6 +2094,11 @@ ReadKnownVMs(const char *jvmCfgName, jbo jvmCfg = fopen(jvmCfgName, "r"); if (jvmCfg == NULL) { diff -Nru openjdk-17-17.0.3+7/debian/patches/hotspot-mips-align.diff openjdk-17-17.0.4+8/debian/patches/hotspot-mips-align.diff --- openjdk-17-17.0.3+7/debian/patches/hotspot-mips-align.diff 2021-05-27 09:28:46.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/hotspot-mips-align.diff 2022-05-02 18:22:30.000000000 +0000 @@ -1,6 +1,6 @@ --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp -@@ -414,7 +414,7 @@ int ZeroInterpreter::native_entry(Method +@@ -418,7 +418,7 @@ int ZeroInterpreter::native_entry(Method ThreadStateTransition::transition_from_java(thread, _thread_in_native); // Make the call diff -Nru openjdk-17-17.0.3+7/debian/patches/jaw-classpath.diff openjdk-17-17.0.4+8/debian/patches/jaw-classpath.diff --- openjdk-17-17.0.3+7/debian/patches/jaw-classpath.diff 2021-05-27 09:32:44.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/jaw-classpath.diff 2022-07-20 09:27:43.000000000 +0000 @@ -2,7 +2,7 @@ --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp -@@ -460,6 +460,7 @@ void os::init_system_properties_values() +@@ -461,6 +461,7 @@ void os::init_system_properties_values() if (!set_boot_path('/', ':')) { vm_exit_during_initialization("Failed setting boot class path.", NULL); } diff -Nru openjdk-17-17.0.3+7/debian/patches/jaw-optional.diff openjdk-17-17.0.4+8/debian/patches/jaw-optional.diff --- openjdk-17-17.0.3+7/debian/patches/jaw-optional.diff 2020-11-07 11:16:22.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/jaw-optional.diff 2022-05-02 18:23:11.000000000 +0000 @@ -6,7 +6,7 @@ --- a/src/java.desktop/share/classes/java/awt/Toolkit.java +++ b/src/java.desktop/share/classes/java/awt/Toolkit.java -@@ -600,7 +600,11 @@ public abstract class Toolkit { +@@ -602,7 +602,11 @@ public abstract class Toolkit { toolkit = new HeadlessToolkit(toolkit); } if (!GraphicsEnvironment.isHeadless()) { diff -Nru openjdk-17-17.0.3+7/debian/patches/jdk-getAccessibleValue.diff openjdk-17-17.0.4+8/debian/patches/jdk-getAccessibleValue.diff --- openjdk-17-17.0.3+7/debian/patches/jdk-getAccessibleValue.diff 2021-04-08 07:39:38.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/jdk-getAccessibleValue.diff 2022-07-20 09:27:01.000000000 +0000 @@ -79,7 +79,7 @@ --- a/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/src/java.desktop/share/classes/javax/swing/JTable.java -@@ -8402,7 +8402,12 @@ public class JTable extends JComponent i +@@ -9223,7 +9223,12 @@ public class JTable extends JComponent i * @return the AccessibleAction, or null */ public AccessibleAction getAccessibleAction() { @@ -93,7 +93,7 @@ } /** -@@ -8424,7 +8429,12 @@ public class JTable extends JComponent i +@@ -9245,7 +9250,12 @@ public class JTable extends JComponent i * null */ public AccessibleSelection getAccessibleSelection() { @@ -107,7 +107,7 @@ } /** -@@ -8434,7 +8444,12 @@ public class JTable extends JComponent i +@@ -9255,7 +9265,12 @@ public class JTable extends JComponent i * @return the AccessibleText, or null */ public AccessibleText getAccessibleText() { @@ -121,63 +121,7 @@ } /** -@@ -8444,7 +8459,12 @@ public class JTable extends JComponent i - * @return the AccessibleValue, or null - */ - public AccessibleValue getAccessibleValue() { -- return getCurrentAccessibleContext().getAccessibleValue(); -+ AccessibleContext ac = getCurrentAccessibleContext(); -+ if (ac != null) { -+ return ac.getAccessibleValue(); -+ } else { -+ return null; -+ } - } - - -@@ -9204,7 +9224,12 @@ public class JTable extends JComponent i - * @return the AccessibleAction, or null - */ - public AccessibleAction getAccessibleAction() { -- return getCurrentAccessibleContext().getAccessibleAction(); -+ AccessibleContext ac = getCurrentAccessibleContext(); -+ if (ac != null) { -+ return ac.getAccessibleAction(); -+ } else { -+ return null; -+ } - } - - /** -@@ -9226,7 +9251,12 @@ public class JTable extends JComponent i - * null - */ - public AccessibleSelection getAccessibleSelection() { -- return getCurrentAccessibleContext().getAccessibleSelection(); -+ AccessibleContext ac = getCurrentAccessibleContext(); -+ if (ac != null) { -+ return ac.getAccessibleSelection(); -+ } else { -+ return null; -+ } - } - - /** -@@ -9236,7 +9266,12 @@ public class JTable extends JComponent i - * @return the AccessibleText, or null - */ - public AccessibleText getAccessibleText() { -- return getCurrentAccessibleContext().getAccessibleText(); -+ AccessibleContext ac = getCurrentAccessibleContext(); -+ if (ac != null) { -+ return ac.getAccessibleText(); -+ } else { -+ return null; -+ } - } - - /** -@@ -9246,7 +9281,12 @@ public class JTable extends JComponent i +@@ -9265,7 +9280,12 @@ public class JTable extends JComponent i * @return the AccessibleValue, or null */ public AccessibleValue getAccessibleValue() { @@ -193,7 +137,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 -@@ -6550,7 +6550,7 @@ final public class AccessBridge { +@@ -6562,7 +6562,7 @@ final public class AccessBridge { public AccessibleSelection getAccessibleSelection() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null && isLeaf) { @@ -202,7 +146,7 @@ } else { return this; } -@@ -6565,7 +6565,7 @@ final public class AccessBridge { +@@ -6577,7 +6577,7 @@ final public class AccessBridge { public AccessibleText getAccessibleText() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null) { @@ -211,7 +155,7 @@ } else { return null; } -@@ -6580,7 +6580,7 @@ final public class AccessBridge { +@@ -6592,7 +6592,7 @@ final public class AccessBridge { public AccessibleValue getAccessibleValue() { AccessibleContext ac = getCurrentAccessibleContext(); if (ac != null) { diff -Nru openjdk-17-17.0.3+7/debian/patches/jtreg-location.diff openjdk-17-17.0.4+8/debian/patches/jtreg-location.diff --- openjdk-17-17.0.3+7/debian/patches/jtreg-location.diff 2021-05-27 09:29:01.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/jtreg-location.diff 2022-05-02 18:22:50.000000000 +0000 @@ -1,6 +1,6 @@ --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 -@@ -1022,7 +1022,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JTREG], +@@ -1029,7 +1029,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JTREG], AC_MSG_ERROR([jtreg home directory from --with-jtreg=$with_jtreg does not exist]) fi @@ -9,7 +9,7 @@ AC_MSG_ERROR([jtreg home directory from --with-jtreg=$with_jtreg is not a valid jtreg home]) fi -@@ -1036,7 +1036,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JTREG], +@@ -1043,7 +1043,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JTREG], AC_MSG_WARN([Ignoring JT_HOME pointing to invalid directory: $JT_HOME]) JT_HOME= else @@ -18,7 +18,7 @@ AC_MSG_WARN([Ignoring JT_HOME which is not a valid jtreg home: $JT_HOME]) JT_HOME= else -@@ -1052,7 +1052,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JTREG], +@@ -1059,7 +1059,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JTREG], if test "x$JTREGEXE" != x; then # That's good, now try to derive JT_HOME JT_HOME=`(cd $($DIRNAME $JTREGEXE)/.. && pwd)` @@ -29,7 +29,7 @@ else --- a/make/RunTests.gmk +++ b/make/RunTests.gmk -@@ -837,7 +837,7 @@ define SetupRunJtregTestBody +@@ -846,7 +846,7 @@ define SetupRunJtregTestBody $1_COMMAND_LINE := \ $$(JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \ diff -Nru openjdk-17-17.0.3+7/debian/patches/libpcsclite-dlopen.diff openjdk-17-17.0.4+8/debian/patches/libpcsclite-dlopen.diff --- openjdk-17-17.0.3+7/debian/patches/libpcsclite-dlopen.diff 2021-02-25 09:49:28.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/libpcsclite-dlopen.diff 2022-05-02 18:22:35.000000000 +0000 @@ -1,6 +1,6 @@ --- a/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java +++ b/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java -@@ -48,6 +48,7 @@ class PlatformPCSC { +@@ -46,6 +46,7 @@ class PlatformPCSC { private final static String PROP_NAME = "sun.security.smartcardio.library"; @@ -8,7 +8,7 @@ private final static String LIB1 = "/usr/$LIBISA/libpcsclite.so"; private final static String LIB2 = "/usr/local/$LIBISA/libpcsclite.so"; private final static String PCSC_FRAMEWORK = "/System/Library/Frameworks/PCSC.framework/Versions/Current/PCSC"; -@@ -100,40 +101,9 @@ class PlatformPCSC { +@@ -98,40 +99,9 @@ class PlatformPCSC { if (lib.length() != 0) { return lib; } diff -Nru openjdk-17-17.0.3+7/debian/patches/m68k-support.diff openjdk-17-17.0.4+8/debian/patches/m68k-support.diff --- openjdk-17-17.0.3+7/debian/patches/m68k-support.diff 2021-05-27 09:29:19.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/m68k-support.diff 2022-05-02 18:23:01.000000000 +0000 @@ -1042,7 +1042,7 @@ $(eval $(call SetupExecute, gen_x11wrappers, \ --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp -@@ -238,7 +238,7 @@ template class CHeapObj ALL +@@ -239,7 +239,7 @@ template class CHeapObj ALL void operator delete(void* p) { FreeHeap(p); } void operator delete [] (void* p) { FreeHeap(p); } @@ -1051,7 +1051,7 @@ // Base class for objects allocated on the stack only. // Calling new or delete will result in fatal error. -@@ -249,7 +249,7 @@ class StackObj ALLOCATION_SUPER_CLASS_SP +@@ -250,7 +250,7 @@ class StackObj ALLOCATION_SUPER_CLASS_SP void* operator new [](size_t size) throw(); void operator delete(void* p); void operator delete [](void* p); @@ -1060,7 +1060,7 @@ // Base class for objects stored in Metaspace. // Calling delete will result in fatal error. -@@ -356,7 +356,7 @@ class MetaspaceObj { +@@ -372,7 +372,7 @@ class MetaspaceObj { // that should be read-only by default. See symbol.hpp for an example. This function // is used by the templates in metaspaceClosure.hpp static bool is_read_only_by_default() { return false; } @@ -1069,7 +1069,7 @@ // Base class for classes that constitute name spaces. -@@ -441,7 +441,7 @@ protected: +@@ -457,7 +457,7 @@ protected: void operator delete(void* p); void operator delete [](void* p); @@ -1090,7 +1090,7 @@ #endif // SHARE_OOPS_CONSTMETHOD_HPP --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp -@@ -316,6 +316,6 @@ class oopDesc { +@@ -315,6 +315,6 @@ class oopDesc { // Avoid include gc_globals.hpp in oop.inline.hpp DEBUG_ONLY(bool get_UseParallelGC();) DEBUG_ONLY(bool get_UseG1GC();) diff -Nru openjdk-17-17.0.3+7/debian/patches/multiple-pkcs11-library-init.diff openjdk-17-17.0.4+8/debian/patches/multiple-pkcs11-library-init.diff --- openjdk-17-17.0.3+7/debian/patches/multiple-pkcs11-library-init.diff 2021-05-27 09:28:57.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/multiple-pkcs11-library-init.diff 2022-05-02 18:22:44.000000000 +0000 @@ -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 -@@ -986,6 +987,8 @@ final class Config { +@@ -1019,6 +1020,8 @@ final class Config { handleStartupErrors = ERR_IGNORE_LIB; } else if (val.equals("halt")) { handleStartupErrors = ERR_HALT; @@ -26,7 +26,7 @@ } --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java -@@ -177,26 +177,37 @@ public final class SunPKCS11 extends Aut +@@ -179,26 +179,37 @@ public final class SunPKCS11 extends Aut String nssLibraryDirectory = config.getNssLibraryDirectory(); String nssSecmodDirectory = config.getNssSecmodDirectory(); boolean nssOptimizeSpace = config.getNssOptimizeSpace(); diff -Nru openjdk-17-17.0.3+7/debian/patches/reproducible-build-jmod.diff openjdk-17-17.0.4+8/debian/patches/reproducible-build-jmod.diff --- openjdk-17-17.0.3+7/debian/patches/reproducible-build-jmod.diff 2021-02-20 10:40:51.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/reproducible-build-jmod.diff 2022-07-20 09:30:22.000000000 +0000 @@ -12,7 +12,7 @@ --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk -@@ -223,6 +223,15 @@ endif +@@ -230,6 +230,15 @@ endif # Create jmods in the support dir and then move them into place to keep the # module path in $(IMAGES_OUTPUTDIR)/jmods valid at all times. @@ -28,9 +28,9 @@ $(eval $(call SetupExecute, create_$(JMOD_FILE), \ WARN := Creating $(INTERIM_MSG)$(JMOD_FILE), \ DEPS := $(DEPS), \ -@@ -233,7 +242,7 @@ $(eval $(call SetupExecute, create_$(JMO - --target-platform '$(OPENJDK_MODULE_TARGET_PLATFORM)' \ +@@ -241,7 +250,7 @@ $(eval $(call SetupExecute, create_$(JMO --module-path $(JMODS_DIR) $(JMOD_FLAGS) \ + $(JMOD_SOURCE_DATE) \ $(JMODS_SUPPORT_DIR)/$(JMOD_FILE), \ - POST_COMMAND := $(MV) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE) $(JMODS_DIR)/$(JMOD_FILE), \ + POST_COMMAND := $(if $(use_strip_ndt),strip-nondeterminism --timestamp $(DSN_TIMESTAMP) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE) && )$(MV) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE) $(JMODS_DIR)/$(JMOD_FILE), \ diff -Nru openjdk-17-17.0.3+7/debian/patches/reproducible-properties-timestamp.diff openjdk-17-17.0.4+8/debian/patches/reproducible-properties-timestamp.diff --- openjdk-17-17.0.3+7/debian/patches/reproducible-properties-timestamp.diff 2021-04-08 07:39:56.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/reproducible-properties-timestamp.diff 2022-05-02 18:23:03.000000000 +0000 @@ -3,7 +3,7 @@ Forwarded: no --- a/src/java.base/share/classes/java/util/Properties.java +++ b/src/java.base/share/classes/java/util/Properties.java -@@ -914,7 +914,7 @@ public class Properties extends Hashtabl +@@ -903,7 +903,7 @@ public class Properties extends Hashtabl if (comments != null) { writeComments(bw, comments); } @@ -12,7 +12,7 @@ bw.newLine(); synchronized (this) { for (Map.Entry e : entrySet()) { -@@ -1566,4 +1566,22 @@ public class Properties extends Hashtabl +@@ -1555,4 +1555,22 @@ public class Properties extends Hashtabl } this.map = map; } diff -Nru openjdk-17-17.0.3+7/debian/patches/riscv64.diff openjdk-17-17.0.4+8/debian/patches/riscv64.diff --- openjdk-17-17.0.3+7/debian/patches/riscv64.diff 2021-05-27 09:32:51.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/riscv64.diff 2022-07-20 09:30:18.000000000 +0000 @@ -58,7 +58,7 @@ exit $exitcode --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp -@@ -2506,6 +2506,8 @@ void os::get_summary_cpu_info(char* cpui +@@ -2563,6 +2563,8 @@ void os::get_summary_cpu_info(char* cpui strncpy(cpuinfo, "IA64", length); #elif defined(PPC) strncpy(cpuinfo, "PPC64", length); diff -Nru openjdk-17-17.0.3+7/debian/patches/s390x-opt.diff openjdk-17-17.0.4+8/debian/patches/s390x-opt.diff --- openjdk-17-17.0.3+7/debian/patches/s390x-opt.diff 2021-04-08 07:39:34.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/s390x-opt.diff 2022-07-20 09:27:23.000000000 +0000 @@ -1,6 +1,6 @@ --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 -@@ -699,6 +699,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], +@@ -721,6 +721,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], fi elif test "x$FLAGS_CPU" = xs390x; then $1_CFLAGS_CPU="-mbackchain -march=z10" diff -Nru openjdk-17-17.0.3+7/debian/patches/series openjdk-17-17.0.4+8/debian/patches/series --- openjdk-17-17.0.3+7/debian/patches/series 2022-04-24 14:02:05.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/series 2022-07-20 09:30:14.000000000 +0000 @@ -31,7 +31,7 @@ jaw-optional.diff reproducible-character-data.diff reproducible-module-info.diff -reproducible-copyright-headers.diff +#reproducible-copyright-headers.diff riscv64.diff reproducible-build-jmod.diff mips.diff diff -Nru openjdk-17-17.0.3+7/debian/patches/system-pcsclite.diff openjdk-17-17.0.4+8/debian/patches/system-pcsclite.diff --- openjdk-17-17.0.3+7/debian/patches/system-pcsclite.diff 2021-05-27 09:28:42.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/patches/system-pcsclite.diff 2022-07-20 09:27:11.000000000 +0000 @@ -70,7 +70,7 @@ --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in -@@ -764,6 +764,7 @@ TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TR +@@ -773,6 +773,7 @@ TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TR # Build setup USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ diff -Nru openjdk-17-17.0.3+7/debian/rules openjdk-17-17.0.4+8/debian/rules --- openjdk-17-17.0.3+7/debian/rules 2022-04-24 14:00:25.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/rules 2022-07-22 08:57:45.000000000 +0000 @@ -172,7 +172,7 @@ ifneq (,$(filter $(distrel), precise trusty)) with_docs = endif -with_check = disabled for this upload +#with_check = disabled for this upload with_wqy_zenhai = $(if $(filter $(distrel),lenny),,yes) @@ -1871,7 +1871,7 @@ is_release = yes #is_release = git_project = jdk17u -git_tag = jdk-17.0.3+7 +git_tag = jdk-17.0.4+8 package_version = $(subst jdk-,,$(git_tag)) package_version = $(shell echo $(PKGVERSION) | sed 's/-[^-][^-]*$$//') ifneq ($(is_release),yes) @@ -1895,8 +1895,6 @@ -type f -print -delete; \ rm -v -rf $$d/src/java.desktop/share/native/libsplashscreen/giflib; \ rm -v -rf $$d/src/java.desktop/share/native/libsplashscreen/libpng; \ - rm -v -f $$d/src/java.desktop/share/native/liblcms/cms*.c; \ - rm -v -f $$d/src/java.desktop/share/native/liblcms/lcms2*.h; \ rm -v -rf $$d/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE; \ esac; \ mv $$d $(topdir); \ @@ -1904,9 +1902,13 @@ rm -f $(topdir)/.hgtags; \ rm -f $(topdir)/.gitattributes; \ rm -rf $(topdir)/.github; \ - tar cfJ ../$(basename)_$(package_version).orig.tar.xz $(topdir); \ + XZ_OPT=-9v tar cfJ ../$(basename)_$(package_version).orig.tar.xz $(topdir); \ rm -rf $(topdir) +# keep these in the tarball, older lcms are not supported + rm -v -f $$d/src/java.desktop/share/native/liblcms/cms*.c; \ + rm -v -f $$d/src/java.desktop/share/native/liblcms/lcms2*.h; \ + rm -rf $(origdir) binary: binary-arch binary-indep diff -Nru openjdk-17-17.0.3+7/debian/source/lintian-overrides openjdk-17-17.0.4+8/debian/source/lintian-overrides --- openjdk-17-17.0.3+7/debian/source/lintian-overrides 2018-04-28 20:18:11.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/source/lintian-overrides 2022-05-03 17:51:02.000000000 +0000 @@ -1,2 +1,2 @@ # parts of the test suite, not installed -openjdk-11 source: source-is-missing +openjdk-17 source: source-is-missing diff -Nru openjdk-17-17.0.3+7/debian/tests/jtreg-autopkgtest.in openjdk-17-17.0.4+8/debian/tests/jtreg-autopkgtest.in --- openjdk-17-17.0.3+7/debian/tests/jtreg-autopkgtest.in 2021-07-01 11:08:20.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/tests/jtreg-autopkgtest.in 2022-07-20 17:10:26.000000000 +0000 @@ -83,7 +83,7 @@ output_dir="${AUTOPKGTEST_ARTIFACTS}/${testsuite}/" # retry tests with "fail" or "error" status at most 3 times -for i in 0 1 2 3; do +for i in 0 1; do # save each try under its own folder to preserve history report_path="${i}/JTreport" report_dir="${output_dir}/${report_path}" diff -Nru openjdk-17-17.0.3+7/debian/tests/jtreg-autopkgtest.sh openjdk-17-17.0.4+8/debian/tests/jtreg-autopkgtest.sh --- openjdk-17-17.0.3+7/debian/tests/jtreg-autopkgtest.sh 2021-07-01 16:10:48.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/tests/jtreg-autopkgtest.sh 2022-07-20 17:10:42.000000000 +0000 @@ -83,7 +83,7 @@ output_dir="${AUTOPKGTEST_ARTIFACTS}/${testsuite}/" # retry tests with "fail" or "error" status at most 3 times -for i in 0 1 2 3; do +for i in 0 1; do # save each try under its own folder to preserve history report_path="${i}/JTreport" report_dir="${output_dir}/${report_path}" diff -Nru openjdk-17-17.0.3+7/debian/watch openjdk-17-17.0.4+8/debian/watch --- openjdk-17-17.0.3+7/debian/watch 2021-06-18 14:32:44.000000000 +0000 +++ openjdk-17-17.0.4+8/debian/watch 2022-07-20 09:21:18.000000000 +0000 @@ -1,4 +1,4 @@ version=4 opts="filenamemangle=s%(?:.*?)?jdk-(\d[\d.]*\+\d[\d]*)\.tar\.gz%-$1.tar.gz%, dversionmangle=s/~/+/" \ - https://github.com/openjdk/jdk17/tags \ + https://github.com/openjdk/jdk17u/tags \ (?:.*?/)?jdk-(\d[\d.]*\+\d[\d]*)\.tar\.gz debian uupdate diff -Nru openjdk-17-17.0.3+7/.jcheck/conf openjdk-17-17.0.4+8/.jcheck/conf --- openjdk-17-17.0.3+7/.jcheck/conf 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/.jcheck/conf 2022-07-14 08:05:38.000000000 +0000 @@ -1,7 +1,7 @@ [general] project=jdk-updates jbs=JDK -version=17.0.3 +version=17.0.4 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists diff -Nru openjdk-17-17.0.3+7/make/autoconf/basic_tools.m4 openjdk-17-17.0.4+8/make/autoconf/basic_tools.m4 --- openjdk-17-17.0.3+7/make/autoconf/basic_tools.m4 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/autoconf/basic_tools.m4 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -270,6 +270,8 @@ TAR_TYPE="bsd" elif test "x$($TAR -v | $GREP "bsdtar")" != "x"; then TAR_TYPE="bsd" + elif test "x$($TAR --version | $GREP "busybox")" != "x"; then + TAR_TYPE="busybox" elif test "x$OPENJDK_BUILD_OS" = "xaix"; then TAR_TYPE="aix" fi @@ -281,9 +283,12 @@ TAR_SUPPORTS_TRANSFORM="true" elif test "x$TAR_TYPE" = "aix"; then # -L InputList of aix tar: name of file listing the files and directories - # that need to be archived or extracted + # that need to be archived or extracted TAR_INCLUDE_PARAM="L" TAR_SUPPORTS_TRANSFORM="false" + elif test "x$TAR_TYPE" = "xbusybox"; then + TAR_INCLUDE_PARAM="T" + TAR_SUPPORTS_TRANSFORM="false" else TAR_INCLUDE_PARAM="I" TAR_SUPPORTS_TRANSFORM="false" @@ -356,6 +361,18 @@ fi AC_SUBST(IS_GNU_TIME) + # 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"` + if test "x$check_date" != x; then + AC_MSG_RESULT([yes]) + IS_GNU_DATE=yes + else + AC_MSG_RESULT([no]) + IS_GNU_DATE=no + fi + AC_SUBST(IS_GNU_DATE) + if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then UTIL_REQUIRE_PROGS(DSYMUTIL, dsymutil) UTIL_REQUIRE_PROGS(MIG, mig) diff -Nru openjdk-17-17.0.3+7/make/autoconf/boot-jdk.m4 openjdk-17-17.0.4+8/make/autoconf/boot-jdk.m4 --- openjdk-17-17.0.3+7/make/autoconf/boot-jdk.m4 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/autoconf/boot-jdk.m4 2022-07-14 08:05:38.000000000 +0000 @@ -357,6 +357,16 @@ # Finally, set some other options... + # Determine if the boot jdk jar supports the --date option + if $JAR --help 2>&1 | $GREP -q "\-\-date=TIMESTAMP"; then + BOOT_JDK_JAR_SUPPORTS_DATE=true + else + BOOT_JDK_JAR_SUPPORTS_DATE=false + fi + AC_MSG_CHECKING([if Boot JDK jar supports --date=TIMESTAMP]) + AC_MSG_RESULT([$BOOT_JDK_JAR_SUPPORTS_DATE]) + AC_SUBST(BOOT_JDK_JAR_SUPPORTS_DATE) + # When compiling code to be executed by the Boot JDK, force compatibility with the # oldest supported bootjdk. OLDEST_BOOT_JDK=`$ECHO $DEFAULT_ACCEPTABLE_BOOT_VERSIONS \ diff -Nru openjdk-17-17.0.3+7/make/autoconf/flags-cflags.m4 openjdk-17-17.0.4+8/make/autoconf/flags-cflags.m4 --- openjdk-17-17.0.3+7/make/autoconf/flags-cflags.m4 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/autoconf/flags-cflags.m4 2022-07-14 08:05:38.000000000 +0000 @@ -95,8 +95,24 @@ # info flags for toolchains unless we know they work. # See JDK-8207057. ASFLAGS_DEBUG_SYMBOLS="" + + # Debug prefix mapping if supported by compiler + DEBUG_PREFIX_CFLAGS= + # Debug symbols if test "x$TOOLCHAIN_TYPE" = xgcc; then + if test "x$ALLOW_ABSOLUTE_PATHS_IN_OUTPUT" = "xfalse"; then + # Check if compiler supports -fdebug-prefix-map. If so, use that to make + # the debug symbol paths resolve to paths relative to the workspace root. + workspace_root_trailing_slash="${WORKSPACE_ROOT%/}/" + DEBUG_PREFIX_CFLAGS="-fdebug-prefix-map=${workspace_root_trailing_slash}=" + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${DEBUG_PREFIX_CFLAGS}], + IF_FALSE: [ + DEBUG_PREFIX_CFLAGS= + ] + ) + fi + CFLAGS_DEBUG_SYMBOLS="-g" ASFLAGS_DEBUG_SYMBOLS="-g" elif test "x$TOOLCHAIN_TYPE" = xclang; then @@ -108,6 +124,11 @@ CFLAGS_DEBUG_SYMBOLS="-Z7" fi + if test "x$DEBUG_PREFIX_CFLAGS" != x; then + CFLAGS_DEBUG_SYMBOLS="$CFLAGS_DEBUG_SYMBOLS $DEBUG_PREFIX_CFLAGS" + ASFLAGS_DEBUG_SYMBOLS="$ASFLAGS_DEBUG_SYMBOLS $DEBUG_PREFIX_CFLAGS" + fi + AC_SUBST(CFLAGS_DEBUG_SYMBOLS) AC_SUBST(ASFLAGS_DEBUG_SYMBOLS) ]) @@ -159,6 +180,7 @@ clang) DISABLE_WARNING_PREFIX="-Wno-" + BUILD_CC_DISABLE_WARNING_PREFIX="-Wno-" CFLAGS_WARNINGS_ARE_ERRORS="-Werror" # Additional warnings that are not activated by -Wall and -Wextra @@ -782,10 +804,8 @@ test "x$ENABLE_REPRODUCIBLE_BUILD" = xtrue; then # There is a known issue with the pathmap if the mapping is made to the # empty string. Add a minimal string "s" as prefix to work around this. - workspace_root_win=`$FIXPATH_BASE print "${WORKSPACE_ROOT%/}"` # PATHMAP_FLAGS is also added to LDFLAGS in flags-ldflags.m4. - PATHMAP_FLAGS="-pathmap:${workspace_root_win//\//\\\\}=s \ - -pathmap:${workspace_root_win}=s" + PATHMAP_FLAGS="-pathmap:${WORKSPACE_ROOT}=s" FILE_MACRO_CFLAGS="$PATHMAP_FLAGS" FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${FILE_MACRO_CFLAGS}], PREFIX: $3, diff -Nru openjdk-17-17.0.3+7/make/autoconf/help.m4 openjdk-17-17.0.4+8/make/autoconf/help.m4 --- openjdk-17-17.0.3+7/make/autoconf/help.m4 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/autoconf/help.m4 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. # 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 @@ AC_DEFUN_ONCE([HELP_SETUP_DEPENDENCY_HELP], [ - UTIL_LOOKUP_PROGS(PKGHANDLER, zypper apt-get yum brew port pkgutil pkgadd pacman) + UTIL_LOOKUP_PROGS(PKGHANDLER, zypper apt-get yum brew port pkgutil pkgadd pacman apk) ]) AC_DEFUN([HELP_MSG_MISSING_DEPENDENCY], @@ -58,6 +58,8 @@ zypper_help $MISSING_DEPENDENCY ;; *pacman) pacman_help $MISSING_DEPENDENCY ;; + *apk) + apk_help $MISSING_DEPENDENCY ;; esac if test "x$PKGHANDLER_COMMAND" != x; then @@ -184,6 +186,27 @@ PKGHANDLER_COMMAND="" } +apk_help() { + case $1 in + devkit) + PKGHANDLER_COMMAND="sudo apk add alpine-sdk linux-headers" ;; + alsa) + PKGHANDLER_COMMAND="sudo apk add alsa-lib-dev" ;; + cups) + PKGHANDLER_COMMAND="sudo apk add cups-dev" ;; + fontconfig) + PKGHANDLER_COMMAND="sudo apk add fontconfig-dev" ;; + freetype) + PKGHANDLER_COMMAND="sudo apk add freetype-dev" ;; + harfbuzz) + PKGHANDLER_COMMAND="sudo apk add harfbuzz-dev" ;; + x11) + PKGHANDLER_COMMAND="sudo apk add libxtst-dev libxt-dev libxrender-dev libxrandr-dev" ;; + ccache) + PKGHANDLER_COMMAND="sudo apk add ccache" ;; + esac +} + # This function will check if we're called from the "configure" wrapper while # printing --help. If so, we will print out additional information that can # only be extracted within the autoconf script, and then exit. This must be diff -Nru openjdk-17-17.0.3+7/make/autoconf/jdk-options.m4 openjdk-17-17.0.4+8/make/autoconf/jdk-options.m4 --- openjdk-17-17.0.3+7/make/autoconf/jdk-options.m4 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/autoconf/jdk-options.m4 2022-07-14 08:05:38.000000000 +0000 @@ -216,6 +216,12 @@ AC_MSG_ERROR([Copyright year must have a value]) elif test "x$with_copyright_year" != x; then COPYRIGHT_YEAR="$with_copyright_year" + elif test "x$SOURCE_DATE_EPOCH" != x; then + if test "x$IS_GNU_DATE" = xyes; then + COPYRIGHT_YEAR=`date --date=@$SOURCE_DATE_EPOCH +%Y` + else + COPYRIGHT_YEAR=`date -j -f %s $SOURCE_DATE_EPOCH +%Y` + fi else COPYRIGHT_YEAR=`$DATE +'%Y'` fi diff -Nru openjdk-17-17.0.3+7/make/autoconf/spec.gmk.in openjdk-17-17.0.4+8/make/autoconf/spec.gmk.in --- openjdk-17-17.0.3+7/make/autoconf/spec.gmk.in 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/autoconf/spec.gmk.in 2022-07-14 08:05:38.000000000 +0000 @@ -364,6 +364,9 @@ CREATE_BUILDJDK:=@CREATE_BUILDJDK@ EXTERNAL_BUILDJDK:=@EXTERNAL_BUILDJDK@ +# Whether the boot jdk jar supports --date=TIMESTAMP +BOOT_JDK_JAR_SUPPORTS_DATE:=@BOOT_JDK_JAR_SUPPORTS_DATE@ + # When compiling Java source to be run by the boot jdk # use these extra flags, eg -source 6 -target 6 BOOT_JDK_SOURCETARGET:=@BOOT_JDK_SOURCETARGET@ @@ -700,6 +703,7 @@ CP:=@CP@ CUT:=@CUT@ DATE:=@DATE@ +IS_GNU_DATE:=@IS_GNU_DATE@ DIFF:=@DIFF@ DIRNAME:=@DIRNAME@ DSYMUTIL:=@DSYMUTIL@ diff -Nru openjdk-17-17.0.3+7/make/autoconf/util.m4 openjdk-17-17.0.4+8/make/autoconf/util.m4 --- openjdk-17-17.0.3+7/make/autoconf/util.m4 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/autoconf/util.m4 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -236,13 +236,15 @@ # $2: input date/time string AC_DEFUN([UTIL_GET_EPOCH_TIMESTAMP], [ - timestamp=$($DATE --utc --date=$2 +"%s" 2> /dev/null) - if test "x$timestamp" = x; then - # GNU date format did not work, try BSD date options - timestamp=$($DATE -j -f "%F %T" "$2" "+%s" 2> /dev/null) + if test "x$IS_GNU_DATE" = xyes; then + # GNU date + timestamp=$($DATE --utc --date=$2 +"%s" 2> /dev/null) + else + # BSD date + timestamp=$($DATE -u -j -f "%F %T" "$2" "+%s" 2> /dev/null) if test "x$timestamp" = x; then # Perhaps the time was missing - timestamp=$($DATE -j -f "%F %T" "$2 00:00:00" "+%s" 2> /dev/null) + timestamp=$($DATE -u -j -f "%F %T" "$2 00:00:00" "+%s" 2> /dev/null) # If this did not work, we give up and return the empty string fi fi diff -Nru openjdk-17-17.0.3+7/make/common/JarArchive.gmk openjdk-17-17.0.4+8/make/common/JarArchive.gmk --- openjdk-17-17.0.3+7/make/common/JarArchive.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/common/JarArchive.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -193,7 +193,8 @@ $1_UPDATE_CONTENTS=\ if [ "`$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'`" -gt "0" ]; then \ $(ECHO) " updating" `$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'` files && \ - $$($1_JAR_CMD) $$($1_JAR_UPDATE_OPTIONS) $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents; \ + $(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \ + $$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted; \ fi $$(NEWLINE) # The s-variants of the above macros are used when the jar is created from scratch. # NOTICE: please leave the parentheses space separated otherwise the AIX build will break! @@ -212,25 +213,29 @@ | $(SED) 's|$$(src)/|-C $$(src) |g' >> \ $$($1_BIN)/_the.$$($1_JARNAME)_contents) $$(NEWLINE) ) endif - $1_SUPDATE_CONTENTS=$$($1_JAR_CMD) $$($1_JAR_UPDATE_OPTIONS) $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE) + $1_SUPDATE_CONTENTS=\ + $(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \ + $$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted $$(NEWLINE) # Use a slightly shorter name for logging, but with enough path to identify this jar. $1_NAME:=$$(subst $$(OUTPUTDIR)/,,$$($1_JAR)) + # If reproducible build and the boot jdk jar supports --date option + # then specify the --date using SOURCE_DATE in ISO-8601 + $1_JAR_OPTIONS := + ifeq ($$(ENABLE_REPRODUCIBLE_BUILD), true) + ifeq ($$(BOOT_JDK_JAR_SUPPORTS_DATE), true) + $1_JAR_OPTIONS += --date $(SOURCE_DATE_ISO_8601) + endif + endif ifneq (,$$($1_CHECK_COMPRESS_JAR)) - $1_JAR_CREATE_OPTIONS := c0fm - $1_JAR_UPDATE_OPTIONS := u0f - ifeq ($(COMPRESS_JARS), true) - $1_JAR_CREATE_OPTIONS := cfm - $1_JAR_UPDATE_OPTIONS := uf + ifneq ($(COMPRESS_JARS), true) + $1_JAR_OPTIONS += --no-compress endif - else - $1_JAR_CREATE_OPTIONS := cfm - $1_JAR_UPDATE_OPTIONS := uf endif # Include all variables of significance in the vardeps file - $1_VARDEPS := $$($1_JAR_CMD) $$($1_JAR_CREATE_OPTIONS) $$($1_MANIFEST) \ + $1_VARDEPS := $$($1_JAR_CMD) $$($1_JAR_OPTIONS) $$($1_MANIFEST) \ $$($1_JARMAIN) $$($1_EXTRA_MANIFEST_ATTR) $$($1_ORIG_DEPS) $$($1_SRCS) \ $$($1_INCLUDES) $$($1_EXCLUDES) $$($1_EXCLUDE_FILES) $$($1_EXTRA_FILES) $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BIN)/_the.$$($1_JARNAME).vardeps) @@ -255,7 +260,7 @@ $$(if $$($1_EXTRA_MANIFEST_ATTR), \ $(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \ $(ECHO) Creating $$($1_NAME) $$(NEWLINE) \ - $$($1_JAR_CMD) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \ + $$($1_JAR_CMD) --create $$($1_JAR_OPTIONS) --file $$@ --manifest $$($1_MANIFEST_FILE) $$(NEWLINE) \ $$($1_SCAPTURE_CONTENTS) \ $$($1_SCAPTURE_METAINF) \ $$($1_SUPDATE_CONTENTS) \ diff -Nru openjdk-17-17.0.3+7/make/common/NativeCompilation.gmk openjdk-17-17.0.4+8/make/common/NativeCompilation.gmk --- openjdk-17-17.0.3+7/make/common/NativeCompilation.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/common/NativeCompilation.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -358,6 +358,20 @@ # Compile as preprocessed assembler file $1_FLAGS := $(BASIC_ASFLAGS) $$($1_BASE_ASFLAGS) $1_COMPILER := $(AS) + + # gcc assembly files must contain an appropriate relative .file + # path for reproducible builds. + ifeq ($(TOOLCHAIN_TYPE), gcc) + # If no absolute paths allowed, work out relative source file path + # for assembly .file substitution, otherwise use full file path + ifeq ($(ALLOW_ABSOLUTE_PATHS_IN_OUTPUT), false) + $1_REL_ASM_SRC := $$(call RelativePath, $$($1_FILE), $(WORKSPACE_ROOT)) + else + $1_REL_ASM_SRC := $$($1_FILE) + endif + $1_FLAGS := $$($1_FLAGS) -DASSEMBLY_SRC_FILE='"$$($1_REL_ASM_SRC)"' \ + -include $(TOPDIR)/make/data/autoheaders/assemblyprefix.h + endif else ifneq ($$(filter %.cpp %.cc %.mm, $$($1_FILENAME)), ) # Compile as a C++ or Objective-C++ file $1_FLAGS := $(CFLAGS_CCACHE) $$($1_USE_PCH_FLAGS) $$($1_BASE_CXXFLAGS) \ @@ -389,6 +403,12 @@ $1_OBJ_DEPS := $$($1_SRC_FILE) $$($$($1_BASE)_COMPILE_VARDEPS_FILE) \ $$($$($1_BASE)_EXTRA_DEPS) $$($1_VARDEPS_FILE) $1_COMPILE_OPTIONS := $$($1_FLAGS) $(CC_OUT_OPTION)$$($1_OBJ) $$($1_SRC_FILE) + # For reproducible builds with gcc ensure random symbol generation is seeded deterministically + ifeq ($(TOOLCHAIN_TYPE), gcc) + ifeq ($$(ENABLE_REPRODUCIBLE_BUILD), true) + $1_COMPILE_OPTIONS += -frandom-seed="$$($1_FILENAME)" + endif + endif $$($1_OBJ_JSON): $$($1_OBJ_DEPS) $$(call WriteCompileCommandsFragment, $$@, $$(PWD), $$($1_SRC_FILE), \ diff -Nru openjdk-17-17.0.3+7/make/conf/test-dependencies openjdk-17-17.0.4+8/make/conf/test-dependencies --- openjdk-17-17.0.3+7/make/conf/test-dependencies 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/conf/test-dependencies 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. # 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,19 +25,19 @@ # Versions and download locations for dependencies used by pre-submit testing. -BOOT_JDK_VERSION=16 +BOOT_JDK_VERSION=17 JTREG_VERSION=6 JTREG_BUILD=1 GTEST_VERSION=1.8.1 -LINUX_X64_BOOT_JDK_FILENAME=openjdk-17.0.1_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk17.0.1/2a2082e5a09d4267845be086888add4f/12/GPL/openjdk-17.0.1_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=1c0a73cbb863aad579b967316bf17673b8f98a9bb938602a140ba2e5c38f880a +LINUX_X64_BOOT_JDK_FILENAME=openjdk-17.0.2_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.2%2B8/OpenJDK17U-jdk_x64_linux_hotspot_17.0.2_8.tar.gz +LINUX_X64_BOOT_JDK_SHA256=288f34e3ba8a4838605636485d0365ce23e57d5f2f68997ac4c2e4c01967cd48 -WINDOWS_X64_BOOT_JDK_FILENAME=openjdk-17.0.1_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk17.0.1/2a2082e5a09d4267845be086888add4f/12/GPL/openjdk-17.0.1_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=329900a6673b237b502bdcf77bc334da34bc91355c5fd2d457fc00f53fd71ef1 +WINDOWS_X64_BOOT_JDK_FILENAME=openjdk-17.0.2_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.2%2B8/OpenJDK17U-jdk_x64_windows_hotspot_17.0.2_8.zip +WINDOWS_X64_BOOT_JDK_SHA256=d083479ca927dce2f586f779373d895e8bf668c632505740279390384edf03fa -MACOS_X64_BOOT_JDK_FILENAME=openjdk-17.0.1_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk17.0.1/2a2082e5a09d4267845be086888add4f/12/GPL/openjdk-17.0.1_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=6ccb35800e723cabe15af60e67099d1a07c111d2d3208aa75523614dde68bee1 +MACOS_X64_BOOT_JDK_FILENAME=openjdk-17.0.2_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.2%2B8/OpenJDK17U-jdk_x64_mac_hotspot_17.0.2_8.tar.gz +MACOS_X64_BOOT_JDK_SHA256=3630e21a571b7180876bf08f85d0aac0bdbb3267b2ae9bd242f4933b21f9be32 diff -Nru openjdk-17-17.0.3+7/make/conf/version-numbers.conf openjdk-17-17.0.4+8/make/conf/version-numbers.conf --- openjdk-17-17.0.3+7/make/conf/version-numbers.conf 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/conf/version-numbers.conf 2022-07-14 08:05:38.000000000 +0000 @@ -28,12 +28,12 @@ DEFAULT_VERSION_FEATURE=17 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=3 +DEFAULT_VERSION_UPDATE=4 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2022-04-19 +DEFAULT_VERSION_DATE=2022-07-19 DEFAULT_VERSION_CLASSFILE_MAJOR=61 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 diff -Nru openjdk-17-17.0.3+7/make/CreateJmods.gmk openjdk-17-17.0.4+8/make/CreateJmods.gmk --- openjdk-17-17.0.3+7/make/CreateJmods.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/CreateJmods.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -221,6 +221,13 @@ JMOD_FLAGS += --exclude '**{_the.*,_*.marker*,*.diz,*.debuginfo,*.dSYM/**,*.dSYM}' endif +# For reproducible builds specify the jmod --date using SOURCE_DATE in ISO-8601 +ifeq ($(ENABLE_REPRODUCIBLE_BUILD), true) + JMOD_SOURCE_DATE := --date $(SOURCE_DATE_ISO_8601) +else + JMOD_SOURCE_DATE := +endif + # Create jmods in the support dir and then move them into place to keep the # module path in $(IMAGES_OUTPUTDIR)/jmods valid at all times. $(eval $(call SetupExecute, create_$(JMOD_FILE), \ @@ -232,6 +239,7 @@ COMMAND := $(JMOD) create --module-version $(VERSION_SHORT) \ --target-platform '$(OPENJDK_MODULE_TARGET_PLATFORM)' \ --module-path $(JMODS_DIR) $(JMOD_FLAGS) \ + $(JMOD_SOURCE_DATE) \ $(JMODS_SUPPORT_DIR)/$(JMOD_FILE), \ POST_COMMAND := $(MV) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE) $(JMODS_DIR)/$(JMOD_FILE), \ )) diff -Nru openjdk-17-17.0.3+7/make/data/autoheaders/assemblyprefix.h openjdk-17-17.0.4+8/make/data/autoheaders/assemblyprefix.h --- openjdk-17-17.0.3+7/make/data/autoheaders/assemblyprefix.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/autoheaders/assemblyprefix.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,29 @@ +# +# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +// ASSEMBLY_SRC_FILE gets replaced by relative or absolute file path +// in NativeCompilation.gmk for gcc tooling on Linux. This ensures a +// reproducible object file through a predictable value of the STT_FILE +// symbol, and subsequently a reproducible .debuginfo. +.file ASSEMBLY_SRC_FILE + diff -Nru openjdk-17-17.0.3+7/make/data/publicsuffixlist/public_suffix_list.dat openjdk-17-17.0.4+8/make/data/publicsuffixlist/public_suffix_list.dat --- openjdk-17-17.0.3+7/make/data/publicsuffixlist/public_suffix_list.dat 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/publicsuffixlist/public_suffix_list.dat 2022-07-14 08:05:38.000000000 +0000 @@ -175,17 +175,21 @@ // aq : https://en.wikipedia.org/wiki/.aq aq -// ar : https://nic.ar/nic-argentina/normativa-vigente +// ar : https://nic.ar/es/nic-argentina/normativa ar +bet.ar com.ar +coop.ar edu.ar gob.ar gov.ar int.ar mil.ar musica.ar +mutual.ar net.ar org.ar +senasa.ar tur.ar // arpa : https://en.wikipedia.org/wiki/.arpa @@ -258,7 +262,7 @@ vic.gov.au wa.gov.au // 4LDs -education.tas.edu.au +// education.tas.edu.au - Removed at the request of the Department of Education Tasmania schools.nsw.edu.au // aw : https://en.wikipedia.org/wiki/.aw @@ -456,6 +460,7 @@ am.br anani.br aparecida.br +app.br arq.br art.br ato.br @@ -463,6 +468,7 @@ barueri.br belem.br bhz.br +bib.br bio.br blog.br bmd.br @@ -477,14 +483,19 @@ com.br contagem.br coop.br +coz.br cri.br cuiaba.br curitiba.br def.br +des.br +det.br +dev.br ecn.br eco.br edu.br emp.br +enf.br eng.br esp.br etc.br @@ -500,6 +511,7 @@ foz.br fst.br g12.br +geo.br ggf.br goiania.br gov.br @@ -543,6 +555,7 @@ jus.br leg.br lel.br +log.br londrina.br macapa.br maceio.br @@ -575,6 +588,7 @@ radio.br rec.br recife.br +rep.br ribeirao.br rio.br riobranco.br @@ -585,6 +599,7 @@ santoandre.br saobernardo.br saogonca.br +seg.br sjc.br slg.br slz.br @@ -592,6 +607,7 @@ srv.br taxi.br tc.br +tec.br teo.br the.br tmp.br @@ -722,7 +738,6 @@ // cl : https://www.nic.cl // Confirmed by .CL registry cl -aprendemas.cl co.cl gob.cl gov.cl @@ -827,7 +842,13 @@ inf.cu // cv : https://en.wikipedia.org/wiki/.cv +// cv : http://www.dns.cv/tldcv_portal/do?com=DS;5446457100;111;+PAGE(4000018)+K-CAT-CODIGO(RDOM)+RCNT(100); <- registration rules cv +com.cv +edu.cv +int.cv +nome.cv +org.cv // cw : http://www.una.cw/cw_registry/ // Confirmed by registry 2013-03-26 @@ -895,16 +916,18 @@ sld.do web.do -// dz : https://en.wikipedia.org/wiki/.dz +// dz : http://www.nic.dz/images/pdf_nic/charte.pdf dz +art.dz +asso.dz com.dz +edu.dz +gov.dz org.dz net.dz -gov.dz -edu.dz -asso.dz pol.dz -art.dz +soc.dz +tm.dz // ec : http://www.nic.ec/reg/paso1.asp // Submitted by registry @@ -1002,6 +1025,10 @@ *.fk // fm : https://en.wikipedia.org/wiki/.fm +com.fm +edu.fm +net.fm +org.fm fm // fo : https://en.wikipedia.org/wiki/.fo @@ -1041,6 +1068,8 @@ gb // gd : https://en.wikipedia.org/wiki/.gd +edu.gd +gov.gd gd // ge : http://www.nic.net.ge/policy_en.pdf @@ -1132,7 +1161,7 @@ // gs : https://en.wikipedia.org/wiki/.gs gs -// gt : http://www.gt/politicas_de_registro.html +// gt : https://www.gt/sitio/registration_policy.php?lang=en gt com.gt edu.gt @@ -1156,6 +1185,7 @@ web.gu // gw : https://en.wikipedia.org/wiki/.gw +// gw : https://nic.gw/regras/ gw // gy : https://en.wikipedia.org/wiki/.gy @@ -3785,7 +3815,7 @@ // li : https://en.wikipedia.org/wiki/.li li -// lk : http://www.nic.lk/seclevpr.html +// lk : https://www.nic.lk/index.php/domain-registration/lk-domain-naming-structure lk gov.lk sch.lk @@ -4574,15 +4604,17 @@ edu.mx net.mx -// my : http://www.mynic.net.my/ +// my : http://www.mynic.my/ +// Available strings: https://mynic.my/resources/domains/buying-a-domain/ my +biz.my com.my -net.my -org.my -gov.my edu.my +gov.my mil.my name.my +net.my +org.my // mz : http://www.uem.mz/ // Submitted by registry @@ -4679,13 +4711,13 @@ // ccTLD for the Netherlands nl -// no : http://www.norid.no/regelverk/index.en.html -// The Norwegian registry has declined to notify us of updates. The web pages -// referenced below are the official source of the data. There is also an -// announce mailing list: -// https://postlister.uninett.no/sympa/info/norid-diskusjon +// no : https://www.norid.no/en/om-domenenavn/regelverk-for-no/ +// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ +// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ +// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ +// RSS feed: https://teknisk.norid.no/en/feed/ no -// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html +// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ fhs.no vgs.no fylkesbibl.no @@ -4693,13 +4725,13 @@ museum.no idrett.no priv.no -// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html +// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ mil.no stat.no dep.no kommune.no herad.no -// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html +// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ // counties aa.no ah.no @@ -5828,7 +5860,7 @@ org.ps net.ps -// pt : http://online.dns.pt/dns/start_dns +// pt : https://www.dns.pt/en/domain/pt-terms-and-conditions-registration-rules/ pt net.pt gov.pt @@ -6065,8 +6097,10 @@ com.ss edu.ss gov.ss +me.ss net.ss org.ss +sch.ss // st : http://www.nic.st/html/policyrules/ st @@ -6075,7 +6109,6 @@ consulado.st edu.st embaixada.st -gov.st mil.st net.st org.st @@ -6180,29 +6213,22 @@ mil.tm edu.tm -// tn : https://en.wikipedia.org/wiki/.tn -// http://whois.ati.tn/ +// tn : http://www.registre.tn/fr/ +// https://whois.ati.tn/ tn com.tn ens.tn fin.tn gov.tn ind.tn +info.tn intl.tn +mincom.tn nat.tn net.tn org.tn -info.tn perso.tn tourism.tn -edunet.tn -rnrt.tn -rns.tn -rnu.tn -mincom.tn -agrinet.tn -defense.tn -turen.tn // to : https://en.wikipedia.org/wiki/.to // Submitted by registry @@ -6327,7 +6353,6 @@ dn.ua dnepropetrovsk.ua dnipropetrovsk.ua -dominic.ua donetsk.ua dp.ua if.ua @@ -6693,9 +6718,10 @@ edu.vc // ve : https://registro.nic.ve/ -// Submitted by registry +// Submitted by registry nic@nic.ve and nicve@conatel.gob.ve ve arts.ve +bib.ve co.ve com.ve e12.ve @@ -6707,7 +6733,9 @@ int.ve mil.ve net.ve +nom.ve org.ve +rar.ve rec.ve store.ve tec.ve @@ -6786,6 +6814,9 @@ // xn--90ae ("bg", Bulgarian) : BG бг +// xn--mgbcpq6gpa1a ("albahrain", Arabic) : BH +البحرين + // xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY // Operated by .by registry бел @@ -6918,12 +6949,15 @@ // xn--80ao21a ("Kaz", Kazakh) : KZ қаз +// xn--q7ce6a ("Lao", Lao) : LA +ລາວ + // xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK -// http://nic.lk +// https://nic.lk ලංකා // xn--xkc2al3hye2a ("Ilangai", Tamil) : LK -// http://nic.lk +// https://nic.lk இலங்கை // xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA @@ -7043,7 +7077,13 @@ xxx // ye : http://www.y.net.ye/services/domain_name.htm -*.ye +ye +com.ye +edu.ye +gov.ye +net.ye +mil.ye +org.ye // za : https://www.zadna.org.za/content/page/domain-information/ ac.za @@ -7092,7 +7132,7 @@ // newGTLDs -// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2020-04-02T18:20:31Z +// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2021-11-13T15:12:42Z // This list is auto-generated, don't edit it manually. // aaa : 2015-02-26 American Automobile Association, Inc. aaa @@ -7118,7 +7158,7 @@ // able : 2015-06-25 Able Inc. able -// abogado : 2014-04-24 Minds + Machines Group Limited +// abogado : 2014-04-24 Registry Services, LLC abogado // abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre @@ -7175,9 +7215,6 @@ // aig : 2014-12-18 American International Group, Inc. aig -// aigo : 2015-08-06 aigo Digital Technology Co,Ltd. -aigo - // airbus : 2015-07-30 Airbus S.A.S. airbus @@ -7241,7 +7278,7 @@ // android : 2014-08-07 Charleston Road Registry Inc. android -// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +// anquan : 2015-01-08 Beijing Qihu Keji Co., Ltd. anquan // anz : 2015-07-31 Australia and New Zealand Banking Group Limited @@ -7301,7 +7338,7 @@ // audible : 2015-06-25 Amazon Registry Services, Inc. audible -// audio : 2014-03-20 Uniregistry, Corp. +// audio : 2014-03-20 UNR Corp. audio // auspost : 2015-08-13 Australian Postal Corporation @@ -7310,19 +7347,19 @@ // author : 2014-12-18 Amazon Registry Services, Inc. author -// auto : 2014-11-13 Cars Registry Limited +// auto : 2014-11-13 XYZ.COM LLC auto -// autos : 2014-01-09 DERAutos, LLC +// autos : 2014-01-09 XYZ.COM LLC autos // avianca : 2015-01-08 Avianca Holdings S.A. avianca -// aws : 2015-06-25 Amazon Registry Services, Inc. +// aws : 2015-06-25 AWS Registry LLC aws -// axa : 2013-12-19 AXA SA +// axa : 2013-12-19 AXA Group Operations SAS axa // azure : 2014-12-18 Microsoft Corporation @@ -7397,7 +7434,7 @@ // beauty : 2015-12-03 XYZ.COM LLC beauty -// beer : 2014-01-09 Minds + Machines Group Limited +// beer : 2014-01-09 Registry Services, LLC beer // bentley : 2014-12-18 Bentley Motors Limited @@ -7439,7 +7476,7 @@ // black : 2014-01-16 Afilias Limited black -// blackfriday : 2014-01-16 Uniregistry, Corp. +// blackfriday : 2014-01-16 UNR Corp. blackfriday // blockbuster : 2015-07-30 Dish DBS Corporation @@ -7463,7 +7500,7 @@ // bnpparibas : 2014-05-29 BNP Paribas bnpparibas -// boats : 2014-12-04 DERBoats, LLC +// boats : 2014-12-04 XYZ.COM LLC boats // boehringer : 2015-07-09 Boehringer Ingelheim International GmbH @@ -7502,7 +7539,7 @@ // boutique : 2013-11-14 Binky Moon, LLC boutique -// box : 2015-11-12 .BOX INC. +// box : 2015-11-12 Intercap Registry Inc. box // bradesco : 2014-12-18 Banco Bradesco S.A. @@ -7514,7 +7551,7 @@ // broadway : 2014-12-22 Celebrate Broadway, Inc. broadway -// broker : 2014-12-11 Dotbroker Registry Limited +// broker : 2014-12-11 Dog Beach, LLC broker // brother : 2015-01-29 Brother Industries, Ltd. @@ -7586,7 +7623,7 @@ // capitalone : 2015-08-06 Capital One Financial Corporation capitalone -// car : 2015-01-22 Cars Registry Limited +// car : 2015-01-22 XYZ.COM LLC car // caravan : 2013-12-12 Caravan International, Inc. @@ -7604,18 +7641,15 @@ // careers : 2013-10-02 Binky Moon, LLC careers -// cars : 2014-11-13 Cars Registry Limited +// cars : 2014-11-13 XYZ.COM LLC cars -// casa : 2013-11-21 Minds + Machines Group Limited +// casa : 2013-11-21 Registry Services, LLC casa -// case : 2015-09-03 CNH Industrial N.V. +// case : 2015-09-03 Helium TLDs Ltd case -// caseih : 2015-09-03 CNH Industrial N.V. -caseih - // cash : 2014-03-06 Binky Moon, LLC cash @@ -7640,9 +7674,6 @@ // cbs : 2015-08-06 CBS Domains Inc. cbs -// ceb : 2015-04-09 The Corporate Executive Board Company -ceb - // center : 2013-11-07 Binky Moon, LLC center @@ -7655,7 +7686,7 @@ // cfa : 2014-08-28 CFA Institute cfa -// cfd : 2014-12-11 DotCFD Registry Limited +// cfd : 2014-12-11 ShortDot SA cfd // chanel : 2015-04-09 Chanel International B.V. @@ -7679,7 +7710,7 @@ // chintai : 2015-06-11 CHINTAI Corporation chintai -// christmas : 2013-11-21 Uniregistry, Corp. +// christmas : 2013-11-21 UNR Corp. christmas // chrome : 2014-07-24 Charleston Road Registry Inc. @@ -7718,7 +7749,7 @@ // cleaning : 2013-12-05 Binky Moon, LLC cleaning -// click : 2014-06-05 Uniregistry, Corp. +// click : 2014-06-05 UNR Corp. click // clinic : 2014-03-20 Binky Moon, LLC @@ -7733,7 +7764,7 @@ // cloud : 2015-04-16 Aruba PEC S.p.A. cloud -// club : 2013-11-08 .CLUB DOMAINS, LLC +// club : 2013-11-08 Registry Services, LLC club // clubmed : 2015-06-25 Club Méditerranée S.A. @@ -7790,7 +7821,7 @@ // contractors : 2013-09-10 Binky Moon, LLC contractors -// cooking : 2013-11-21 Minds + Machines Group Limited +// cooking : 2013-11-21 Registry Services, LLC cooking // cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. @@ -7823,7 +7854,7 @@ // creditcard : 2014-03-20 Binky Moon, LLC creditcard -// creditunion : 2015-01-22 CUNA Performance Resources, LLC +// creditunion : 2015-01-22 DotCooperation LLC creditunion // cricket : 2014-10-09 dot Cricket Limited @@ -7880,7 +7911,7 @@ // dclk : 2014-11-20 Charleston Road Registry Inc. dclk -// dds : 2015-05-07 Minds + Machines Group Limited +// dds : 2015-05-07 Registry Services, LLC dds // deal : 2015-06-25 Amazon Registry Services, Inc. @@ -7919,7 +7950,7 @@ // desi : 2013-11-14 Desi Networks LLC desi -// design : 2014-11-07 Top Level Design, LLC +// design : 2014-11-07 Registry Services, LLC design // dev : 2014-10-16 Charleston Road Registry Inc. @@ -7931,7 +7962,7 @@ // diamonds : 2013-09-22 Binky Moon, LLC diamonds -// diet : 2014-06-26 Uniregistry, Corp. +// diet : 2014-06-26 UNR Corp. diet // digital : 2014-03-06 Binky Moon, LLC @@ -7991,7 +8022,7 @@ // dunlop : 2015-07-02 The Goodyear Tire & Rubber Company dunlop -// dupont : 2015-06-25 E. I. du Pont de Nemours and Company +// dupont : 2015-06-25 DuPont Specialty Products USA, LLC dupont // durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry @@ -8054,9 +8085,6 @@ // estate : 2013-08-27 Binky Moon, LLC estate -// esurance : 2015-07-23 Esurance Insurance Company -esurance - // etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) etisalat @@ -8111,7 +8139,7 @@ // farmers : 2015-07-09 Farmers Insurance Exchange farmers -// fashion : 2014-07-03 Minds + Machines Group Limited +// fashion : 2014-07-03 Registry Services, LLC fashion // fast : 2014-12-18 Amazon Registry Services, Inc. @@ -8162,16 +8190,16 @@ // fish : 2013-12-12 Binky Moon, LLC fish -// fishing : 2013-11-21 Minds + Machines Group Limited +// fishing : 2013-11-21 Registry Services, LLC fishing -// fit : 2014-11-07 Minds + Machines Group Limited +// fit : 2014-11-07 Registry Services, LLC fit // fitness : 2014-03-06 Binky Moon, LLC fitness -// flickr : 2015-04-02 Yahoo! Domain Services Inc. +// flickr : 2015-04-02 Flickr, Inc. flickr // flights : 2013-12-05 Binky Moon, LLC @@ -8183,7 +8211,7 @@ // florist : 2013-11-07 Binky Moon, LLC florist -// flowers : 2014-10-09 Uniregistry, Corp. +// flowers : 2014-10-09 UNR Corp. flowers // fly : 2014-05-08 Charleston Road Registry Inc. @@ -8204,7 +8232,7 @@ // ford : 2014-11-13 Ford Motor Company ford -// forex : 2014-12-11 Dotforex Registry Limited +// forex : 2014-12-11 Dog Beach, LLC forex // forsale : 2014-05-22 Dog Beach, LLC @@ -8243,10 +8271,7 @@ // fujitsu : 2015-07-30 Fujitsu Limited fujitsu -// fujixerox : 2015-07-23 Xerox DNHC LLC -fujixerox - -// fun : 2016-01-14 DotSpace Inc. +// fun : 2016-01-14 Radix FZC fun // fund : 2014-03-20 Binky Moon, LLC @@ -8273,7 +8298,7 @@ // gallup : 2015-02-19 Gallup, Inc. gallup -// game : 2015-05-28 Uniregistry, Corp. +// game : 2015-05-28 UNR Corp. game // games : 2015-05-28 Dog Beach, LLC @@ -8282,7 +8307,7 @@ // gap : 2015-07-31 The Gap, Inc. gap -// garden : 2014-06-26 Minds + Machines Group Limited +// garden : 2014-06-26 Registry Services, LLC garden // gay : 2019-05-23 Top Level Design, LLC @@ -8411,7 +8436,7 @@ // guide : 2013-09-13 Binky Moon, LLC guide -// guitars : 2013-11-14 Uniregistry, Corp. +// guitars : 2013-11-14 UNR Corp. guitars // guru : 2013-08-27 Binky Moon, LLC @@ -8444,7 +8469,7 @@ // healthcare : 2014-06-12 Binky Moon, LLC healthcare -// help : 2014-06-26 Uniregistry, Corp. +// help : 2014-06-26 UNR Corp. help // helsinki : 2015-02-05 City of Helsinki @@ -8459,7 +8484,7 @@ // hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc. hgtv -// hiphop : 2014-03-06 Uniregistry, Corp. +// hiphop : 2014-03-06 UNR Corp. hiphop // hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc. @@ -8468,7 +8493,7 @@ // hitachi : 2014-10-31 Hitachi, Ltd. hitachi -// hiv : 2014-03-13 Uniregistry, Corp. +// hiv : 2014-03-13 UNR Corp. hiv // hkt : 2015-05-14 PCCW-HKT DataCom Services Limited @@ -8489,7 +8514,7 @@ // homegoods : 2015-07-16 The TJX Companies, Inc. homegoods -// homes : 2014-01-09 DERHomes, LLC +// homes : 2014-01-09 XYZ.COM LLC homes // homesense : 2015-07-16 The TJX Companies, Inc. @@ -8498,16 +8523,16 @@ // honda : 2014-12-18 Honda Motor Co., Ltd. honda -// horse : 2013-11-21 Minds + Machines Group Limited +// horse : 2013-11-21 Registry Services, LLC horse // hospital : 2016-10-20 Binky Moon, LLC hospital -// host : 2014-04-17 DotHost Inc. +// host : 2014-04-17 Radix FZC host -// hosting : 2014-05-29 Uniregistry, Corp. +// hosting : 2014-05-29 UNR Corp. hosting // hot : 2015-08-27 Amazon Registry Services, Inc. @@ -8597,9 +8622,6 @@ // insure : 2014-03-20 Binky Moon, LLC insure -// intel : 2015-08-06 Intel Corporation -intel - // international : 2013-11-07 Binky Moon, LLC international @@ -8630,9 +8652,6 @@ // itv : 2015-07-09 ITV Services Limited itv -// iveco : 2015-09-03 CNH Industrial N.V. -iveco - // jaguar : 2014-11-13 Jaguar Land Rover Ltd jaguar @@ -8642,9 +8661,6 @@ // jcb : 2014-11-20 JCB Co., Ltd. jcb -// jcp : 2015-04-23 JCP Media, Inc. -jcp - // jeep : 2015-07-30 FCA US LLC. jeep @@ -8681,7 +8697,7 @@ // jprs : 2014-09-18 Japan Registry Services Co., Ltd. jprs -// juegos : 2014-03-20 Uniregistry, Corp. +// juegos : 2014-03-20 UNR Corp. juegos // juniper : 2015-07-30 JUNIPER NETWORKS, INC. @@ -8708,6 +8724,9 @@ // kia : 2015-07-09 KIA MOTORS CORPORATION kia +// kids : 2021-08-13 DotKids Foundation Limited +kids + // kim : 2013-09-23 Afilias Limited kim @@ -8786,13 +8805,13 @@ // latrobe : 2014-06-16 La Trobe University latrobe -// law : 2015-01-22 LW TLD Limited +// law : 2015-01-22 Registry Services, LLC law // lawyer : 2014-03-20 Dog Beach, LLC lawyer -// lds : 2014-03-20 IRI Domain Management, LLC ("Applicant") +// lds : 2014-03-20 IRI Domain Management, LLC lds // lease : 2014-03-06 Binky Moon, LLC @@ -8849,7 +8868,7 @@ // linde : 2014-12-04 Linde Aktiengesellschaft linde -// link : 2013-11-14 Uniregistry, Corp. +// link : 2013-11-14 UNR Corp. link // lipsy : 2015-06-25 Lipsy Ltd @@ -8867,7 +8886,7 @@ // llc : 2017-12-14 Afilias Limited llc -// llp : 2019-08-26 Dot Registry LLC +// llp : 2019-08-26 UNR Corp. llp // loan : 2014-11-20 dot Loan Limited @@ -8885,7 +8904,7 @@ // loft : 2015-07-30 Annco, Inc. loft -// lol : 2015-01-30 Uniregistry, Corp. +// lol : 2015-01-30 UNR Corp. lol // london : 2013-11-14 Dot London Domains Limited @@ -8915,10 +8934,7 @@ // lundbeck : 2015-08-06 H. Lundbeck A/S lundbeck -// lupin : 2014-11-07 LUPIN LIMITED -lupin - -// luxe : 2014-01-09 Minds + Machines Group Limited +// luxe : 2014-01-09 Registry Services, LLC luxe // luxury : 2013-10-17 Luxury Partners, LLC @@ -8957,7 +8973,7 @@ // marketing : 2013-11-07 Binky Moon, LLC marketing -// markets : 2014-12-11 Dotmarkets Registry Limited +// markets : 2014-12-11 Dog Beach, LLC markets // marriott : 2014-10-09 Marriott Worldwide Corporation @@ -9005,9 +9021,6 @@ // merckmsd : 2016-07-14 MSD Registry Holdings, Inc. merckmsd -// metlife : 2015-05-07 MetLife Services and Solutions, LLC -metlife - // miami : 2013-12-19 Minds + Machines Group Limited miami @@ -9047,7 +9060,7 @@ // moi : 2014-12-18 Amazon Registry Services, Inc. moi -// mom : 2015-04-16 Uniregistry, Corp. +// mom : 2015-04-16 UNR Corp. mom // monash : 2013-09-30 Monash University @@ -9059,7 +9072,7 @@ // monster : 2015-09-11 XYZ.COM LLC monster -// mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant") +// mormon : 2013-12-05 IRI Domain Management, LLC mormon // mortgage : 2014-03-20 Dog Beach, LLC @@ -9071,7 +9084,7 @@ // moto : 2015-06-04 Motorola Trademark Holdings, LLC moto -// motorcycles : 2014-01-09 DERMotorcycles, LLC +// motorcycles : 2014-01-09 XYZ.COM LLC motorcycles // mov : 2014-01-30 Charleston Road Registry Inc. @@ -9089,6 +9102,9 @@ // mtr : 2015-03-12 MTR Corporation Limited mtr +// music : 2021-05-04 DotMusic Limited +music + // mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC mutual @@ -9098,9 +9114,6 @@ // nagoya : 2013-10-24 GMO Registry, Inc. nagoya -// nationwide : 2015-07-23 Nationwide Mutual Insurance Company -nationwide - // natura : 2015-03-12 NATURA COSMÉTICOS S.A. natura @@ -9122,15 +9135,12 @@ // network : 2013-11-14 Binky Moon, LLC network -// neustar : 2013-12-05 Registry Services, LLC +// neustar : 2013-12-05 NeuStar, Inc. neustar // new : 2014-01-30 Charleston Road Registry Inc. new -// newholland : 2015-09-03 CNH Industrial N.V. -newholland - // news : 2014-12-18 Dog Beach, LLC news @@ -9176,7 +9186,7 @@ // northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC northwesternmutual -// norton : 2014-12-04 Symantec Corporation +// norton : 2014-12-04 NortonLifeLock Inc. norton // now : 2015-06-25 Amazon Registry Services, Inc. @@ -9203,7 +9213,7 @@ // obi : 2014-09-25 OBI Group Holding SE & Co. KGaA obi -// observer : 2015-04-30 Top Level Spectrum, Inc. +// observer : 2015-04-30 Dog Beach, LLC observer // off : 2015-07-23 Johnson Shareholdings, Inc. @@ -9236,15 +9246,12 @@ // ong : 2014-03-06 Public Interest Registry ong -// onl : 2013-09-16 I-Registry Ltd. +// onl : 2013-09-16 iRegistry GmbH onl -// online : 2015-01-15 DotOnline Inc. +// online : 2015-01-15 Radix FZC online -// onyourside : 2015-07-23 Nationwide Mutual Insurance Company -onyourside - // ooo : 2014-01-09 INFIBEAM AVENUES LIMITED ooo @@ -9323,7 +9330,7 @@ // phone : 2016-06-02 Dish DBS Corporation phone -// photo : 2013-11-14 Uniregistry, Corp. +// photo : 2013-11-14 UNR Corp. photo // photography : 2013-09-20 Binky Moon, LLC @@ -9335,7 +9342,7 @@ // physio : 2014-05-01 PhysBiz Pty Ltd physio -// pics : 2013-11-14 Uniregistry, Corp. +// pics : 2013-11-14 UNR Corp. pics // pictet : 2014-06-26 Pictet Europe S.A. @@ -9398,7 +9405,7 @@ // praxi : 2013-12-05 Praxi S.p.A. praxi -// press : 2014-04-03 DotPress Inc. +// press : 2014-04-03 Radix FZC press // prime : 2015-06-25 Amazon Registry Services, Inc. @@ -9422,7 +9429,7 @@ // properties : 2013-12-05 Binky Moon, LLC properties -// property : 2014-05-22 Uniregistry, Corp. +// property : 2014-05-22 UNR Corp. property // protection : 2015-04-23 XYZ.COM LLC @@ -9449,9 +9456,6 @@ // quest : 2015-03-26 XYZ.COM LLC quest -// qvc : 2015-07-30 QVC, Inc. -qvc - // racing : 2014-12-04 Premier Registry Limited racing @@ -9470,7 +9474,7 @@ // realtor : 2014-05-29 Real Estate Domains LLC realtor -// realty : 2015-03-19 Fegistry, LLC +// realty : 2015-03-19 Dog Beach, LLC realty // recipes : 2013-10-17 Binky Moon, LLC @@ -9533,7 +9537,7 @@ // rexroth : 2015-06-18 Robert Bosch GMBH rexroth -// rich : 2013-11-21 I-Registry Ltd. +// rich : 2013-11-21 iRegistry GmbH rich // richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited @@ -9542,9 +9546,6 @@ // ricoh : 2014-11-20 Ricoh Company, Ltd. ricoh -// rightathome : 2015-07-23 Johnson Shareholdings, Inc. -rightathome - // ril : 2015-04-02 Reliance Industries Limited ril @@ -9554,16 +9555,13 @@ // rip : 2014-07-10 Dog Beach, LLC rip -// rmit : 2015-11-19 Royal Melbourne Institute of Technology -rmit - // rocher : 2014-12-18 Ferrero Trading Lux S.A. rocher // rocks : 2013-11-14 Dog Beach, LLC rocks -// rodeo : 2013-12-19 Minds + Machines Group Limited +// rodeo : 2013-12-19 Registry Services, LLC rodeo // rogers : 2015-08-06 Rogers Communications Canada Inc. @@ -9641,7 +9639,7 @@ // sbi : 2015-03-12 STATE BANK OF INDIA sbi -// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION +// sbs : 2014-11-07 ShortDot SA sbs // sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) @@ -9674,9 +9672,6 @@ // scjohnson : 2015-07-23 Johnson Shareholdings, Inc. scjohnson -// scor : 2014-10-31 SCOR SE -scor - // scot : 2014-01-23 Dot Scot Registry Limited scot @@ -9716,7 +9711,7 @@ // sex : 2014-11-13 ICM Registry SX LLC sex -// sexy : 2013-09-11 Uniregistry, Corp. +// sexy : 2013-09-11 UNR Corp. sexy // sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR @@ -9749,7 +9744,7 @@ // shopping : 2016-03-31 Binky Moon, LLC shopping -// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +// shouji : 2015-01-08 Beijing Qihu Keji Co., Ltd. shouji // show : 2015-03-05 Binky Moon, LLC @@ -9758,9 +9753,6 @@ // showtime : 2015-08-06 CBS Domains Inc. showtime -// shriram : 2014-01-23 Shriram Capital Ltd. -shriram - // silk : 2015-06-25 Amazon Registry Services, Inc. silk @@ -9770,7 +9762,7 @@ // singles : 2013-08-27 Binky Moon, LLC singles -// site : 2015-01-15 DotSite Inc. +// site : 2015-01-15 Radix FZC site // ski : 2015-04-09 Afilias Limited @@ -9830,7 +9822,7 @@ // spa : 2019-09-19 Asia Spa and Wellness Promotion Council Limited spa -// space : 2014-04-03 DotSpace Inc. +// space : 2014-04-03 Radix FZC space // sport : 2017-11-16 Global Association of International Sports Federations (GAISF) @@ -9839,9 +9831,6 @@ // spot : 2015-02-26 Amazon Registry Services, Inc. spot -// spreadbetting : 2014-12-11 Dotspreadbetting Registry Limited -spreadbetting - // srl : 2015-05-07 InterNetX, Corp srl @@ -9872,7 +9861,7 @@ // storage : 2014-12-22 XYZ.COM LLC storage -// store : 2015-04-09 DotStore Inc. +// store : 2015-04-09 Radix FZC store // stream : 2016-01-08 dot Stream Limited @@ -9899,7 +9888,7 @@ // support : 2013-10-24 Binky Moon, LLC support -// surf : 2014-01-09 Minds + Machines Group Limited +// surf : 2014-01-09 Registry Services, LLC surf // surgery : 2014-03-20 Binky Moon, LLC @@ -9911,18 +9900,12 @@ // swatch : 2015-01-08 The Swatch Group Ltd swatch -// swiftcover : 2015-07-23 Swiftcover Insurance Services Limited -swiftcover - // swiss : 2014-10-16 Swiss Confederation swiss // sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet sydney -// symantec : 2014-12-04 Symantec Corporation -symantec - // systems : 2013-11-07 Binky Moon, LLC systems @@ -9947,7 +9930,7 @@ // tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" tatar -// tattoo : 2013-08-30 Uniregistry, Corp. +// tattoo : 2013-08-30 UNR Corp. tattoo // tax : 2014-03-20 Binky Moon, LLC @@ -9965,7 +9948,7 @@ // team : 2015-03-05 Binky Moon, LLC team -// tech : 2015-01-30 Personals TLD Inc. +// tech : 2015-01-30 Radix FZC tech // technology : 2013-09-13 Binky Moon, LLC @@ -9992,7 +9975,7 @@ // tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America tiaa -// tickets : 2015-02-05 Accent Media Limited +// tickets : 2015-02-05 XYZ.COM LLC tickets // tienda : 2013-11-14 Binky Moon, LLC @@ -10058,7 +10041,7 @@ // trade : 2014-01-23 Elite Registry Limited trade -// trading : 2014-12-11 Dottrading Registry Limited +// trading : 2014-12-11 Dog Beach, LLC trading // training : 2013-11-07 Binky Moon, LLC @@ -10076,7 +10059,7 @@ // travelersinsurance : 2015-03-26 Travelers TLD, LLC travelersinsurance -// trust : 2014-10-16 NCC Group Inc. +// trust : 2014-10-16 UNR Corp. trust // trv : 2015-03-26 Travelers TLD, LLC @@ -10109,7 +10092,7 @@ // university : 2014-03-06 Binky Moon, LLC university -// uno : 2013-09-11 DotSite Inc. +// uno : 2013-09-11 Radix FZC uno // uol : 2014-05-01 UBN INTERNET LTDA. @@ -10160,7 +10143,7 @@ // vin : 2015-06-18 Binky Moon, LLC vin -// vip : 2015-01-22 Minds + Machines Group Limited +// vip : 2015-01-22 Registry Services, LLC vip // virgin : 2014-09-25 Virgin Enterprises Limited @@ -10181,7 +10164,7 @@ // vlaanderen : 2014-02-06 DNS.be vzw vlaanderen -// vodka : 2013-12-19 Minds + Machines Group Limited +// vodka : 2013-12-19 Registry Services, LLC vodka // volkswagen : 2015-05-14 Volkswagen Group of America Inc. @@ -10223,7 +10206,7 @@ // watch : 2013-11-14 Binky Moon, LLC watch -// watches : 2014-12-22 Richemont DNS Inc. +// watches : 2014-12-22 Afilias Limited watches // weather : 2015-01-08 International Business Machines Corporation @@ -10238,13 +10221,10 @@ // weber : 2015-06-04 Saint-Gobain Weber SA weber -// website : 2014-04-03 DotWebsite Inc. +// website : 2014-04-03 Radix FZC website -// wed : 2013-10-01 Atgron, Inc. -wed - -// wedding : 2014-04-24 Minds + Machines Group Limited +// wedding : 2014-04-24 Registry Services, LLC wedding // weibo : 2015-03-05 Sina Corporation @@ -10286,7 +10266,7 @@ // woodside : 2015-07-09 Woodside Petroleum Limited woodside -// work : 2013-12-19 Minds + Machines Group Limited +// work : 2013-12-19 Registry Services, LLC work // works : 2013-11-14 Binky Moon, LLC @@ -10313,7 +10293,7 @@ // xfinity : 2015-07-09 Comcast IP Holdings I, LLC xfinity -// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +// xihuan : 2015-01-08 Beijing Qihu Keji Co., Ltd. xihuan // xin : 2014-12-11 Elegant Leader Limited @@ -10337,9 +10317,6 @@ // xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED OY 在线 -// xn--3oq18vl8pn36a : 2015-07-02 Volkswagen (China) Investment Co., Ltd. -大众汽车 - // xn--3pxu8k : 2015-01-15 VeriSign Sarl 点看 @@ -10349,7 +10326,7 @@ // xn--45q11c : 2013-11-21 Zodiac Gemini Ltd 八卦 -// xn--4gbrim : 2013-10-04 Fans TLD Limited +// xn--4gbrim : 2013-10-04 Helium TLDs Ltd موقع // xn--55qw42g : 2013-11-08 China Organizational Name Administration Center @@ -10454,7 +10431,7 @@ // xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited 電訊盈科 -// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited +// xn--g2xx48c : 2015-01-30 Nawang Heli(Xiamen) Network Service Co., LTD. 购物 // xn--gckr3f0f : 2015-02-26 Amazon Registry Services, Inc. @@ -10490,9 +10467,6 @@ // xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. 飞利浦 -// xn--kpu716f : 2014-12-22 Richemont DNS Inc. -手表 - // xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd 手机 @@ -10547,9 +10521,6 @@ // xn--p1acf : 2013-12-12 Rusnames Limited рус -// xn--pbt977c : 2014-12-22 Richemont DNS Inc. -珠宝 - // xn--pssy2u : 2015-01-15 VeriSign Sarl 大拿 @@ -10607,10 +10578,10 @@ // xyz : 2013-12-05 XYZ.COM LLC xyz -// yachts : 2014-01-09 DERYachts, LLC +// yachts : 2014-01-09 XYZ.COM LLC yachts -// yahoo : 2015-04-02 Yahoo! Domain Services Inc. +// yahoo : 2015-04-02 Oath Inc. yahoo // yamaxun : 2014-12-18 Amazon Registry Services, Inc. @@ -10622,7 +10593,7 @@ // yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. yodobashi -// yoga : 2014-05-29 Minds + Machines Group Limited +// yoga : 2014-05-29 Registry Services, LLC yoga // yokohama : 2013-12-12 GMO Registry, Inc. @@ -10634,7 +10605,7 @@ // youtube : 2014-05-01 Charleston Road Registry Inc. youtube -// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +// yun : 2015-01-08 Beijing Qihu Keji Co., Ltd. yun // zappos : 2015-06-25 Amazon Registry Services, Inc. @@ -10666,11 +10637,25 @@ inf.ua ltd.ua +// 611coin : https://611project.org/ +611.to + +// Aaron Marais' Gitlab pages: https://lab.aaronleem.co.za +// Submitted by Aaron Marais +graphox.us + +// accesso Technology Group, plc. : https://accesso.com/ +// Submitted by accesso Team +*.devcdnaccesso.com + // Adobe : https://www.adobe.com/ -// Submitted by Ian Boston +// Submitted by Ian Boston and Lars Trieloff adobeaemcloud.com -adobeaemcloud.net *.dev.adobeaemcloud.com +hlx.live +adobeaemcloud.net +hlx.page +hlx3.page // Agnat sp. z o.o. : https://domena.pl // Submitted by Przemyslaw Plewa @@ -10685,6 +10670,10 @@ *.compute.estate *.alces.network +// all-inkl.com : https://all-inkl.com +// Submitted by Werner Kaltofen +kasserver.com + // Altervista: https://www.altervista.org // Submitted by Carlo Cannas altervista.org @@ -10732,6 +10721,10 @@ *.elb.amazonaws.com *.elb.amazonaws.com.cn +// Amazon Global Accelerator : https://aws.amazon.com/global-accelerator/ +// Submitted by Daniel Massaguer +awsglobalaccelerator.com + // Amazon S3 : https://aws.amazon.com/s3/ // Submitted by Luke Wells s3.amazonaws.com @@ -10789,10 +10782,6 @@ s3-website.eu-west-3.amazonaws.com s3-website.us-east-2.amazonaws.com -// Amsterdam Wireless: https://www.amsterdamwireless.nl/ -// Submitted by Imre Jonk -amsw.nl - // Amune : https://amune.org/ // Submitted by Team Amune t3l3p0rt.net @@ -10802,6 +10791,19 @@ // Submitted by Apigee Security Team apigee.io +// Apphud : https://apphud.com +// Submitted by Alexander Selivanov +siiites.com + +// Appspace : https://www.appspace.com +// Submitted by Appspace Security Team +appspacehosted.com +appspaceusercontent.com + +// Appudo UG (haftungsbeschränkt) : https://www.appudo.com +// Submitted by Alexander Hochbaum +appudo.net + // Aptible : https://www.aptible.com/ // Submitted by Thomas Orozco on-aptible.com @@ -10827,15 +10829,27 @@ // Submitted by Vincent Tseng myasustor.com +// Atlassian : https://atlassian.com +// Submitted by Sam Smyth +cdn.prod.atlassian-dev.net + // AVM : https://avm.de // Submitted by Andreas Weise myfritz.net +// AVStack Pte. Ltd. : https://avstack.io +// Submitted by Jasper Hugo +onavstack.net + // AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com // Submitted by James Kennedy *.awdev.ca *.advisor.ws +// AZ.pl sp. z.o.o: https://az.pl +// Submited by Krzysztof Wolski +ecommerce-shop.pl + // b-data GmbH : https://www.b-data.io // Submitted by Olivier Benz b-data.io @@ -10848,9 +10862,17 @@ // Submitted by Petros Angelatos balena-devices.com +// University of Banja Luka : https://unibl.org +// Domains for Republic of Srpska administrative entity. +// Submitted by Marko Ivanovic +rs.ba + // Banzai Cloud -// Submitted by Gabor Kozma +// Submitted by Janos Matyas +*.banzai.cloud app.banzaicloud.io +*.backyards.banzaicloud.io + // BetaInABox // Submitted by Adrian @@ -10860,14 +10882,30 @@ // Submitted by Nathan O'Sullivan bnr.la +// Bitbucket : http://bitbucket.org +// Submitted by Andy Ortlieb +bitbucket.io + // Blackbaud, Inc. : https://www.blackbaud.com // Submitted by Paul Crowder blackbaudcdn.net +// Blatech : http://www.blatech.net +// Submitted by Luke Bratch +of.je + +// Blue Bite, LLC : https://bluebite.com +// Submitted by Joshua Weiss +bluebite.io + // Boomla : https://boomla.com // Submitted by Tibor Halter boomla.net +// Boutir : https://www.boutir.com +// Submitted by Eric Ng Ka Ka +boutir.com + // Boxfuse : https://boxfuse.com // Submitted by Axel Fontaine boxfuse.io @@ -10881,6 +10919,10 @@ bplaced.net square7.net +// Brendly : https://brendly.rs +// Submitted by Dusan Radovanovic +shop.brendly.rs + // BrowserSafetyMark // Submitted by Dave Tharp browsersafetymark.io @@ -10891,46 +10933,54 @@ dh.bytemark.co.uk vm.bytemark.co.uk +// Caf.js Labs LLC : https://www.cafjs.com +// Submitted by Antonio Lain +cafjs.com + // callidomus : https://www.callidomus.com/ // Submitted by Marcus Popp mycd.eu // Carrd : https://carrd.co // Submitted by AJ +drr.ac +uwu.ai carrd.co crd.co -uwu.ai +ju.mp // CentralNic : http://www.centralnic.com/names/domains // Submitted by registry ae.org -ar.com br.com cn.com com.de com.se de.com eu.com -gb.com gb.net -hu.com hu.net jp.net jpn.com -kr.com mex.com -no.com -qc.com ru.com sa.com se.net uk.com uk.net us.com -uy.com za.bz za.com +// No longer operated by CentralNic, these entries should be adopted and/or removed by current operators +// Submitted by Gavin Brown +ar.com +hu.com +kr.com +no.com +qc.com +uy.com + // Africa.com Web Solutions Ltd : https://registry.africa.com // Submitted by Gavin Brown africa.com @@ -10942,6 +10992,7 @@ // Radix FZC : http://domains.in.net // Submitted by Gavin Brown in.net +web.in // US REGISTRY LLC : http://us.org // Submitted by Gavin Brown @@ -10951,6 +11002,16 @@ // Submitted by Gavin Brown co.com +// Roar Domains LLC : https://roar.basketball/ +// Submitted by Gavin Brown +aus.basketball +nz.basketball + +// BRS Media : https://brsmedia.com/ +// Submitted by Gavin Brown +radio.am +radio.fm + // c.la : http://www.c.la/ c.la @@ -10958,31 +11019,31 @@ // Submitted by B. Blechschmidt certmgr.org -// Citrix : https://citrix.com -// Submitted by Alex Stoddard -xenapponazure.com +// Cityhost LLC : https://cityhost.ua +// Submitted by Maksym Rivtin +cx.ua // Civilized Discourse Construction Kit, Inc. : https://www.discourse.org/ // Submitted by Rishabh Nambiar & Michael Brown discourse.group discourse.team -// ClearVox : http://www.clearvox.nl/ -// Submitted by Leon Rowland -virtueeldomein.nl - // Clever Cloud : https://www.clever-cloud.com/ // Submitted by Quentin Adam cleverapps.io // Clerk : https://www.clerk.dev -// Submitted by Colin Sidoti +// Submitted by Colin Sidoti +clerk.app +clerkstage.app *.lcl.dev +*.lclstage.dev *.stg.dev +*.stgstage.dev -// Clic2000 : https://clic2000.fr -// Submitted by Mathilde Blanchemanche -clic2000.net +// ClickRising : https://clickrising.com/ +// Submitted by Umut Gumeli +clickrising.net // Cloud66 : https://www.cloud66.com/ // Submitted by Khash Sajadi @@ -11004,11 +11065,12 @@ cloudcontrolapp.com // Cloudera, Inc. : https://www.cloudera.com/ -// Submitted by Philip Langdale -cloudera.site +// Submitted by Kedarnath Waikar +*.cloudera.site // Cloudflare, Inc. : https://www.cloudflare.com/ -// Submitted by Jake Riesterer +// Submitted by Cloudflare Team +pages.dev trycloudflare.com workers.dev @@ -11049,10 +11111,6 @@ cloudns.pw cloudns.us -// Cloudeity Inc : https://cloudeity.com -// Submitted by Stefan Dimitrov -cloudeity.net - // CNPY : https://cnpy.gdn // Submitted by Angelo Gladding cnpy.gdn @@ -11116,6 +11174,12 @@ cyon.link cyon.site +// Danger Science Group: https://dangerscience.com/ +// Submitted by Skylar MacDonald +fnwk.site +folionetwork.site +platform0.app + // Daplie, Inc : https://daplie.com // Submitted by AJ ONeal daplie.me @@ -11151,18 +11215,41 @@ // Submitted by Paul Biggar builtwithdark.com +// DataDetect, LLC. : https://datadetect.com +// Submitted by Andrew Banchich +demo.datadetect.com +instance.datadetect.com + // Datawire, Inc : https://www.datawire.io // Submitted by Richard Li edgestack.me +// DDNS5 : https://ddns5.com +// Submitted by Cameron Elliott +ddns5.com + // Debian : https://www.debian.org/ // Submitted by Peter Palfrader / Debian Sysadmin Team debian.net +// Deno Land Inc : https://deno.com/ +// Submitted by Luca Casonato +deno.dev +deno-staging.dev + // deSEC : https://desec.io/ // Submitted by Peter Thomassen dedyn.io +// Diher Solutions : https://diher.solutions +// Submitted by Didi Hermawan +*.rss.my.id +*.diher.solutions + +// DNS Africa Ltd https://dns.business +// Submitted by Calvin Browne +jozi.biz + // DNShome : https://www.dnshome.de/ // Submitted by Norbert Auler dnshome.de @@ -11176,6 +11263,10 @@ // Submitted by Paul Fang drayddns.com +// DreamCommerce : https://shoper.pl/ +// Submitted by Konrad Kotarba +shoparena.pl + // DreamHost : http://www.dreamhost.com/ // Submitted by Andrew Farmer dreamhosters.com @@ -11193,6 +11284,13 @@ // Submitted by Richard Harper duckdns.org +// Bip : https://bip.sh +// Submitted by Joel Kennedy +bip.sh + +// bitbridge.net : Submitted by Craig Welch, abeliidev@gmail.com +bitbridge.net + // dy.fi : http://dy.fi/ // Submitted by Heikki Hannikainen dy.fi @@ -11496,6 +11594,14 @@ definima.net definima.io +// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/ +// Submitted by Braxton Huggins +ondigitalocean.app + +// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/ +// Submitted by Robin H. Johnson +*.digitaloceanspaces.com + // dnstrace.pro : https://dnstrace.pro/ // Submitted by Chris Partridge bci.dnstrace.pro @@ -11528,6 +11634,16 @@ // Submitted by Vladimir Dudr e4.cz +// eero : https://eero.com/ +// Submitted by Yue Kang +eero.online +eero-stage.online + +// Elementor : Elementor Ltd. +// Submitted by Anton Barkan +elementor.cloud +elementor.cool + // En root‽ : https://en-root.org // Submitted by Emmanuel Raviart en-root.fr @@ -11535,17 +11651,13 @@ // Enalean SAS: https://www.enalean.com // Submitted by Thomas Cottier mytuleap.com +tuleap-partners.com // ECG Robotics, Inc: https://ecgrobotics.org // Submitted by onred.one staging.onred.one -// Enonic : http://enonic.com/ -// Submitted by Erik Kaareng-Sunde -enonic.io -customer.enonic.io - // EU.org https://eu.org/ // Submitted by Pierre Beyssac eu.org @@ -11605,6 +11717,10 @@ uk.eu.org us.eu.org +// Eurobyte : https://eurobyte.ru +// Submitted by Evgeniy Subbotin +eurodir.ru + // Evennode : http://www.evennode.com/ // Submitted by Michal Kralik eu-1.evennode.com @@ -11715,6 +11831,7 @@ // Fastly Inc. : http://www.fastly.com/ // Submitted by Fastly Security +edgecompute.app fastly-terrarium.com fastlylb.net map.fastlylb.net @@ -11728,16 +11845,11 @@ // FASTVPS EESTI OU : https://fastvps.ru/ // Submitted by Likhachev Vasiliy -fastpanel.direct fastvps-server.com -myfast.space +fastvps.host myfast.host fastvps.site -fastvps.host - -// Featherhead : https://featherhead.xyz/ -// Submitted by Simon Menke -fhapp.xyz +myfast.space // Fedora : https://fedoraproject.org/ // submitted by Patrick Uiterwijk @@ -11749,15 +11861,20 @@ // FearWorks Media Ltd. : https://fearworksmedia.co.uk // submitted by Keith Fairley -conn.uk -copro.uk couk.me ukco.me +conn.uk +copro.uk +hosp.uk // Fermax : https://fermax.com/ // submitted by Koen Van Isterdael mydobiss.com +// FH Muenster : https://www.fh-muenster.de +// Submitted by Robin Naundorf +fh-muenster.io + // Filegear Inc. : https://www.filegear.com // Submitted by Jason Zhu filegear.me @@ -11772,10 +11889,47 @@ // Submitted by Chris Raynor firebaseapp.com +// Firewebkit : https://www.firewebkit.com +// Submitted by Majid Qureshi +fireweb.app + +// FLAP : https://www.flap.cloud +// Submitted by Louis Chemineau +flap.id + +// FlashDrive : https://flashdrive.io +// Submitted by Eric Chan +onflashdrive.app +fldrv.com + +// fly.io: https://fly.io +// Submitted by Kurt Mackey +fly.dev +edgeapp.net +shw.io + // Flynn : https://flynn.io // Submitted by Jonathan Rudenberg flynnhosting.net +// Forgerock : https://www.forgerock.com +// Submitted by Roderick Parr +forgeblocks.com +id.forgerock.io + +// Framer : https://www.framer.com +// Submitted by Koen Rouwhorst +framer.app +framercanvas.com + +// Frusky MEDIA&PR : https://www.frusky.de +// Submitted by Victor Pupynin +*.frusky.de + +// RavPage : https://www.ravpage.co.il +// Submitted by Roni Horowitz +ravpage.co.il + // Frederik Braun https://frederik-braun.com // Submitted by Frederik Braun 0e.vc @@ -11793,6 +11947,14 @@ // Submitted by Daniel Stone freedesktop.org +// freemyip.com : https://freemyip.com +// Submitted by Cadence +freemyip.com + +// FunkFeuer - Verein zur Förderung freier Netze : https://www.funkfeuer.at +// Submitted by Daniel A. Maierhofer +wien.funkfeuer.at + // Futureweb OG : http://www.futureweb.at // Submitted by Andreas Schnederle-Wagner *.futurecms.at @@ -11816,30 +11978,59 @@ // Gentlent, Inc. : https://www.gentlent.com // Submitted by Tom Klein gentapps.com +gentlentapis.com lab.ms +cdn-edges.net + +// Ghost Foundation : https://ghost.org +// Submitted by Matt Hanley +ghost.io + +// GignoSystemJapan: http://gsj.bz +// Submitted by GignoSystemJapan +gsj.bz // GitHub, Inc. // Submitted by Patrick Toomey -github.io githubusercontent.com +githubpreview.dev +github.io // GitLab, Inc. // Submitted by Alex Hanselka gitlab.io +// Gitplac.si - https://gitplac.si +// Submitted by Aljaž Starc +gitapp.si +gitpage.si + // Glitch, Inc : https://glitch.com // Submitted by Mads Hartmann glitch.me +// Global NOG Alliance : https://nogalliance.org/ +// Submitted by Sander Steffann +nog.community + +// Globe Hosting SRL : https://www.globehosting.com/ +// Submitted by Gavin Brown +co.ro +shop.ro + // GMO Pepabo, Inc. : https://pepabo.com/ // Submitted by dojineko lolipop.io // GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/ -// Submitted by Tom Whitwell +// Submitted by Tom Whitwell cloudapps.digital london.cloudapps.digital +// GOV.UK Pay : https://www.payments.service.gov.uk/ +// Submitted by Richard Baker +pymnt.uk + // UKHomeOffice : https://www.gov.uk/government/organisations/home-office // Submitted by Jon Shanks homeoffice.gov.uk @@ -11847,7 +12038,6 @@ // GlobeHosting, Inc. // Submitted by Zoltan Egresi ro.im -shop.ro // GoIP DNS Services : http://www.goip.de // Submitted by Christian Poulter @@ -11861,6 +12051,18 @@ *.0emm.com appspot.com *.r.appspot.com +codespot.com +googleapis.com +googlecode.com +pagespeedmobilizer.com +publishproxy.com +withgoogle.com +withyoutube.com +*.gateway.dev +cloud.goog +translate.goog +*.usercontent.goog +cloudfunctions.net blogspot.ae blogspot.al blogspot.am @@ -11935,24 +12137,20 @@ blogspot.tw blogspot.ug blogspot.vn -cloudfunctions.net -cloud.goog -codespot.com -googleapis.com -googlecode.com -pagespeedmobilizer.com -publishproxy.com -withgoogle.com -withyoutube.com -// Aaron Marais' Gitlab pages: https://lab.aaronleem.co.za -// Submitted by Aaron Marais -graphox.us +// Goupile : https://goupile.fr +// Submitted by Niels Martignene +goupile.fr // Group 53, LLC : https://www.group53.com // Submitted by Tyler Todd awsmppl.com +// GünstigBestellen : https://günstigbestellen.de +// Submitted by Furkan Akkoc +günstigbestellen.de +günstigliefern.de + // Hakaran group: http://hakaran.cz // Submited by Arseniy Sokolov fin.ci @@ -11974,6 +12172,10 @@ hasura.app hasura-app.io +// Heilbronn University of Applied Sciences - Faculty Informatics (GitLab Pages): https://www.hs-heilbronn.de +// Submitted by Richard Zowalla +pages.it.hs-heilbronn.de + // Hepforge : https://www.hepforge.org // Submitted by David Grellscheid hepforge.org @@ -11991,20 +12193,29 @@ development.run ravendb.run +// home.pl S.A.: https://home.pl +// Submited by Krzysztof Wolski +homesklep.pl + +// Hong Kong Productivity Council: https://www.hkpc.org/ +// Submitted by SECaaS Team +secaas.hk + // HOSTBIP REGISTRY : https://www.hostbip.com/ // Submitted by Atanunu Igbunuroghene -bpl.biz orx.biz -ng.city biz.gl -ng.ink col.ng firm.ng gen.ng ltd.ng ngo.ng -ng.school +edu.scot sch.so +org.yt + +// HostyHosting (hostyhosting.com) +hostyhosting.io // Häkkinen.fi // Submitted by Eero Häkkinen @@ -12019,6 +12230,19 @@ // Submitted by Hannu Aronsson iki.fi +// Impertrix Solutions : +// Submitted by Zhixiang Zhao +impertrixcdn.com +impertrix.com + +// Incsub, LLC: https://incsub.com/ +// Submitted by Aaron Edwards +smushcdn.com +wphostedmail.com +wpmucdn.com +tempurl.host +wpmudev.host + // Individual Network Berlin e.V. : https://www.in-berlin.de/ // Submitted by Christian Seitz dyn-berlin.de @@ -12074,6 +12298,14 @@ // Submitted by Wolfgang Schwarz pixolino.com +// Internet-Pro, LLP: https://netangels.ru/ +// Submited by Vasiliy Sheredeko +na4u.ru + +// iopsys software solutions AB : https://iopsys.eu/ +// Submitted by Roman Azarenko +iopsys.se + // IPiFony Systems, Inc. : https://www.ipifony.com/ // Submitted by Matthew Hardeman ipifony.net @@ -12089,6 +12321,92 @@ // Submitted by Yuji Minagawa iobb.net +// Jelastic, Inc. : https://jelastic.com/ +// Submited by Ihor Kolodyuk +mel.cloudlets.com.au +cloud.interhostsolutions.be +users.scale.virtualcloud.com.br +mycloud.by +alp1.ae.flow.ch +appengine.flow.ch +es-1.axarnet.cloud +diadem.cloud +vip.jelastic.cloud +jele.cloud +it1.eur.aruba.jenv-aruba.cloud +it1.jenv-aruba.cloud +keliweb.cloud +cs.keliweb.cloud +oxa.cloud +tn.oxa.cloud +uk.oxa.cloud +primetel.cloud +uk.primetel.cloud +ca.reclaim.cloud +uk.reclaim.cloud +us.reclaim.cloud +ch.trendhosting.cloud +de.trendhosting.cloud +jele.club +amscompute.com +clicketcloud.com +dopaas.com +hidora.com +paas.hosted-by-previder.com +rag-cloud.hosteur.com +rag-cloud-ch.hosteur.com +jcloud.ik-server.com +jcloud-ver-jpc.ik-server.com +demo.jelastic.com +kilatiron.com +paas.massivegrid.com +jed.wafaicloud.com +lon.wafaicloud.com +ryd.wafaicloud.com +j.scaleforce.com.cy +jelastic.dogado.eu +fi.cloudplatform.fi +demo.datacenter.fi +paas.datacenter.fi +jele.host +mircloud.host +paas.beebyte.io +sekd1.beebyteapp.io +jele.io +cloud-fr1.unispace.io +jc.neen.it +cloud.jelastic.open.tim.it +jcloud.kz +upaas.kazteleport.kz +cloudjiffy.net +fra1-de.cloudjiffy.net +west1-us.cloudjiffy.net +jls-sto1.elastx.net +jls-sto2.elastx.net +jls-sto3.elastx.net +faststacks.net +fr-1.paas.massivegrid.net +lon-1.paas.massivegrid.net +lon-2.paas.massivegrid.net +ny-1.paas.massivegrid.net +ny-2.paas.massivegrid.net +sg-1.paas.massivegrid.net +jelastic.saveincloud.net +nordeste-idc.saveincloud.net +j.scaleforce.net +jelastic.tsukaeru.net +sdscloud.pl +unicloud.pl +mircloud.ru +jelastic.regruhosting.ru +enscaled.sg +jele.site +jelastic.team +orangecloud.tn +j.layershift.co.uk +phx.enscaled.us +mircloud.us + // Jino : https://www.jino.ru // Submitted by Sergey Ulyashin myjino.ru @@ -12097,6 +12415,10 @@ *.spectrum.myjino.ru *.vps.myjino.ru +// Jotelulu S.L. : https://jotelulu.com +// Submitted by Daniel Fariña +jotelulu.cloud + // Joyent : https://www.joyent.com/ // Submitted by Brian Bennett *.triton.zone @@ -12128,10 +12450,20 @@ // Submitted by DisposaBoy oya.to +// Katholieke Universiteit Leuven: https://www.kuleuven.be +// Submitted by Abuse KU Leuven +kuleuven.cloud +ezproxy.kuleuven.be + // .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf co.krd edu.krd +// Krellian Ltd. : https://krellian.com +// Submitted by Ben Francis +krellian.net +webthings.io + // LCube - Professional hosting e.K. : https://www.lcube-webhosting.de // Submitted by Lars Laehn git-repos.de @@ -12162,10 +12494,6 @@ // Submitted by Greg Holland app.lmpm.com -// Linki Tools UG : https://linki.tools -// Submitted by Paulo Matos -linkitools.space - // linkyard ldt: https://www.linkyard.ch/ // Submitted by Mario Siegenthaler linkyard.cloud @@ -12174,12 +12502,18 @@ // Linode : https://linode.com // Submitted by members.linode.com -nodebalancer.linode.com +*.nodebalancer.linode.com +*.linodeobjects.com +ip.linodeusercontent.com // LiquidNet Ltd : http://www.liquidnetlimited.com/ // Submitted by Victor Velchev we.bs +// localzone.xyz +// Submitted by Kenny Niehage +localzone.xyz + // Log'in Line : https://www.loginline.com/ // Submitted by Rémi Mach loginline.app @@ -12188,6 +12522,14 @@ loginline.services loginline.site +// Lokalized : https://lokalized.nl +// Submitted by Noah Taheij +servers.run + +// Lõhmus Family, The +// Submitted by Heiki Lõhmus +lohmus.me + // LubMAN UMCS Sp. z o.o : https://lubman.pl/ // Submitted by Ireneusz Maliszewski krasnik.pl @@ -12199,7 +12541,6 @@ // Lug.org.uk : https://lug.org.uk // Submitted by Jon Spriggs -uklugs.org glug.org.uk lug.org.uk lugs.org.uk @@ -12225,6 +12566,7 @@ barsy.org barsy.pro barsy.pub +barsy.ro barsy.shop barsy.site barsy.support @@ -12243,6 +12585,34 @@ // Submitted by Ilya Zaretskiy hb.cldmail.ru +// Mail Transfer Platform : https://www.neupeer.com +// Submitted by Li Hui +cn.vu + +// Maze Play: https://www.mazeplay.com +// Submitted by Adam Humpherys +mazeplay.com + +// mcpe.me : https://mcpe.me +// Submitted by Noa Heyl +mcpe.me + +// McHost : https://mchost.ru +// Submitted by Evgeniy Subbotin +mcdir.me +mcdir.ru +mcpre.ru +vps.mcdir.ru + +// Mediatech : https://mediatech.by +// Submitted by Evgeniy Kozhuhovskiy +mediatech.by +mediatech.dev + +// Medicom Health : https://medicomhealth.com +// Submitted by Michael Olson +hra.health + // Memset hosting : https://www.memset.com // Submitted by Tom Whitwell miniserver.com @@ -12250,7 +12620,7 @@ // MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ // Submitted by Zdeněk Šustr -cloud.metacentrum.cz +*.cloud.metacentrum.cz custom.metacentrum.cz // MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ @@ -12267,11 +12637,29 @@ co.pl // Microsoft Corporation : http://microsoft.com -// Submitted by Mostafa Elzeiny +// Submitted by Mitch Webster *.azurecontainer.io azurewebsites.net azure-mobile.net cloudapp.net +azurestaticapps.net +centralus.azurestaticapps.net +eastasia.azurestaticapps.net +eastus2.azurestaticapps.net +westeurope.azurestaticapps.net +westus2.azurestaticapps.net + +// minion.systems : http://minion.systems +// Submitted by Robert Böttinger +csx.cc + +// Mintere : https://mintere.com/ +// Submitted by Ben Aubin +mintere.site + +// MobileEducation, LLC : https://joinforte.com +// Submitted by Grayson Martin +forte.id // Mozilla Corporation : https://mozilla.com // Submitted by Ben Francis @@ -12287,35 +12675,48 @@ org.ru pp.ru +// Mythic Beasts : https://www.mythic-beasts.com +// Submitted by Paul Cammish +hostedpi.com +customer.mythic-beasts.com +caracal.mythic-beasts.com +fentiger.mythic-beasts.com +lynx.mythic-beasts.com +ocelot.mythic-beasts.com +oncilla.mythic-beasts.com +onza.mythic-beasts.com +sphinx.mythic-beasts.com +vs.mythic-beasts.com +x.mythic-beasts.com +yali.mythic-beasts.com +cust.retrosnub.co.uk + // Nabu Casa : https://www.nabucasa.com // Submitted by Paulus Schoutsen ui.nabu.casa // Names.of.London : https://names.of.london/ -// Submitted by James Stevens or +// Submitted by James Stevens or pony.club of.fashion -on.fashion -of.football in.london of.london +from.marketing +with.marketing for.men +repair.men and.mom for.mom for.one +under.one for.sale -of.work +that.win +from.work to.work -// NCTU.ME : https://nctu.me/ -// Submitted by Tocknicsu -nctu.me - // Netlify : https://www.netlify.com // Submitted by Jessica Parsons -bitballoon.com netlify.app -netlify.com // Neustar Inc. // Submitted by Trung Tran @@ -12333,6 +12734,20 @@ // Submitted by Jeff Wheelhouse nfshost.com +// Noop : https://noop.app +// Submitted by Nathaniel Schweinberg +*.developer.app +noop.app + +// Northflank Ltd. : https://northflank.com/ +// Submitted by Marco Suter +*.northflank.app +*.code.run + +// Noticeable : https://noticeable.io +// Submitted by Laurent Pellegrino +noticeable.news + // Now-DNS : https://now-dns.com // Submitted by Steve Russell dnsking.ch @@ -12471,60 +12886,6 @@ // Submitted by Matthew Brown nyc.mn -// NymNom : https://nymnom.com/ -// Submitted by NymNom -nom.ae -nom.af -nom.ai -nom.al -nym.by -nom.bz -nym.bz -nom.cl -nym.ec -nom.gd -nom.ge -nom.gl -nym.gr -nom.gt -nym.gy -nym.hk -nom.hn -nym.ie -nom.im -nom.ke -nym.kz -nym.la -nym.lc -nom.li -nym.li -nym.lt -nym.lu -nom.lv -nym.me -nom.mk -nym.mn -nym.mx -nom.nu -nym.nz -nym.pe -nym.pt -nom.pw -nom.qa -nym.ro -nom.rs -nom.si -nym.sk -nom.st -nym.su -nym.sx -nom.tj -nym.tw -nom.ug -nom.uy -nom.vc -nom.vg - // Observable, Inc. : https://observablehq.com // Submitted by Mike Bostock static.observableusercontent.com @@ -12533,35 +12894,66 @@ // Submitted by Andrew Sampson cya.gg +// OMG.LOL : +// Submitted by Adam Newbold +omg.lol + // Omnibond Systems, LLC. : https://www.omnibond.com // Submitted by Cole Estep cloudycluster.net +// OmniWe Limited: https://omniwe.com +// Submitted by Vicary Archangel +omniwe.site + +// One.com: https://www.one.com/ +// Submitted by Jacob Bunk Nielsen +service.one + // One Fold Media : http://www.onefoldmedia.com/ // Submitted by Eddie Jones nid.io +// Open Social : https://www.getopensocial.com/ +// Submitted by Alexander Varwijk +opensocial.site + // OpenCraft GmbH : http://opencraft.com/ // Submitted by Sven Marnach opencraft.hosting +// OpenResearch GmbH: https://openresearch.com/ +// Submitted by Philipp Schmid +orsites.com + // Opera Software, A.S.A. // Submitted by Yngve Pettersen operaunite.com -// Oursky Limited : https://skygear.io/ -// Submited by Skygear Developer +// Oursky Limited : https://authgear.com/, https://skygear.io/ +// Submited by Authgear Team , Skygear Developer +authgear-staging.com +authgearapps.com skygearapp.com // OutSystems // Submitted by Duarte Santos outsystemscloud.com +// OVHcloud: https://ovhcloud.com +// Submitted by Vincent Cassé +*.webpaas.ovh.net +*.hosting.ovh.net + // OwnProvider GmbH: http://www.ownprovider.com // Submitted by Jan Moennich ownprovider.com own.pm +// OwO : https://whats-th.is/ +// Submitted by Dean Sheather +*.owo.codes + // OX : http://www.ox.rs // Submitted by Adam Grand ox.rs @@ -12578,6 +12970,21 @@ // Submitted by Jason Kriss pagefrontapp.com +// PageXL : https://pagexl.com +// Submitted by Yann Guichard +pagexl.com + +// Paywhirl, Inc : https://paywhirl.com/ +// Submitted by Daniel Netzer +*.paywhirl.com + +// pcarrier.ca Software Inc: https://pcarrier.ca/ +// Submitted by Pierre Carrier +bar0.net +bar1.net +bar2.net +rdv.to + // .pl domains (grandfathered) art.pl gliwice.pl @@ -12599,14 +13006,22 @@ // Submitted by Kenneth Van Alstyne perspecta.cloud +// PE Ulyanov Kirill Sergeevich : https://airy.host +// Submitted by Kirill Ulyanov +lk3.ru + // Planet-Work : https://www.planet-work.com/ // Submitted by Frédéric VANNIÈRE on-web.fr // Platform.sh : https://platform.sh // Submitted by Nikola Kotur -*.platform.sh +bc.platform.sh +ent.platform.sh +eu.platform.sh +us.platform.sh *.platformsh.site +*.tst.site // Platter: https://platter.dev // Submitted by Patrick Flor @@ -12614,6 +13029,12 @@ platter-app.dev platterp.us +// Plesk : https://www.plesk.com/ +// Submitted by Anton Akhtyamov +pdns.page +plesk.page +pleskns.com + // Port53 : https://port53.io/ // Submitted by Maximilian Schieder dyn53.io @@ -12622,6 +13043,17 @@ // Submitted by Zulfais co.bn +// Postman, Inc : https://postman.com +// Submitted by Rahul Dhawan +postman-echo.com +pstmn.io +mock.pstmn.io +httpbin.org + +//prequalifyme.today : https://prequalifyme.today +//Submitted by DeepakTiwari deepak@ivylead.io +prequalifyme.today + // prgmr.com : https://prgmr.com/ // Submitted by Sarah Newman xen.prgmr.com @@ -12651,6 +13083,15 @@ // Submitted by Kor Nielsen pubtls.org +// PythonAnywhere LLP: https://www.pythonanywhere.com +// Submitted by Giles Thomas +pythonanywhere.com +eu.pythonanywhere.com + +// QOTO, Org. +// Submitted by Jeffrey Phillips Freeman +qoto.io + // Qualifio : https://qualifio.com/ // Submitted by Xavier De Cock qualifioapp.com @@ -12659,6 +13100,14 @@ // Submitted by Dani Biro qbuser.com +// Rad Web Hosting: https://radwebhosting.com +// Submitted by Scott Claeys +cloudsite.builders + +// Redgate Software: https://red-gate.com +// Submitted by Andrew Farries +instances.spawn.cc + // Redstar Consultants : https://www.redstarconsultants.com/ // Submitted by Jons Slemmer instantcloud.cn @@ -12696,6 +13145,10 @@ rackmaze.com rackmaze.net +// Rakuten Games, Inc : https://dev.viberplay.io +// Submitted by Joshua Zhang +g.vbrplsbx.io + // Rancher Labs, Inc : https://rancher.com // Submitted by Vincent Fiduccia *.on-k3s.io @@ -12718,6 +13171,7 @@ // Repl.it : https://repl.it // Submitted by Mason Clayton repl.co +id.repl.co repl.run // Resin.io : https://resin.io @@ -12732,13 +13186,33 @@ // Revitalised Limited : http://www.revitalised.co.uk // Submitted by Jack Price wellbeingzone.eu -ptplus.fit wellbeingzone.co.uk +// Rico Developments Limited : https://adimo.co +// Submitted by Colin Brown +adimo.co.uk + +// Riseup Networks : https://riseup.net +// Submitted by Micah Anderson +itcouldbewor.se + // Rochester Institute of Technology : http://www.rit.edu/ // Submitted by Jennifer Herting git-pages.rit.edu +// Rusnames Limited: http://rusnames.ru/ +// Submitted by Sergey Zotov +биз.рус +ком.рус +крым.рус +мир.рус +мск.рус +орг.рус +самара.рус +сочи.рус +спб.рус +я.рус + // Sandstorm Development Group, Inc. : https://sandcats.io/ // Submitted by Asheesh Laroia sandcats.io @@ -12755,6 +13229,7 @@ // Scottish Government: https://www.gov.scot // Submitted by Martin Ellis gov.scot +service.gov.scot // Scry Security : http://www.scrysec.com // Submitted by Shante Adam @@ -12773,16 +13248,37 @@ myfirewall.org spdns.org +// Seidat : https://www.seidat.com +// Submitted by Artem Kondratev +seidat.net + +// Sellfy : https://sellfy.com +// Submitted by Yuriy Romadin +sellfy.store + // Senseering GmbH : https://www.senseering.de // Submitted by Felix Mönckemeyer senseering.net +// Sendmsg: https://www.sendmsg.co.il +// Submitted by Assaf Stern +minisite.ms + +// Service Magnet : https://myservicemagnet.com +// Submitted by Dave Sanders +magnet.page + // Service Online LLC : http://drs.ua/ // Submitted by Serhii Bulakh biz.ua co.ua pp.ua +// Shift Crypto AG : https://shiftcrypto.ch +// Submitted by alex +shiftcrypto.dev +shiftcrypto.io + // ShiftEdit : https://shiftedit.net/ // Submitted by Adam Jimenez shiftedit.io @@ -12791,6 +13287,10 @@ // Submitted by Alex Bowers myshopblocks.com +// Shopify : https://www.shopify.com +// Submitted by Alex Richter +myshopify.com + // Shopit : https://www.shopitcommerce.com/ // Submitted by Craig McMahon shopitsite.com @@ -12821,16 +13321,47 @@ alpha.bounty-full.com beta.bounty-full.com +// Small Technology Foundation : https://small-tech.org +// Submitted by Aral Balkan +small-web.org + +// Smoove.io : https://www.smoove.io/ +// Submitted by Dan Kozak +vp4.me + +// Snowplow Analytics : https://snowplowanalytics.com/ +// Submitted by Ian Streeter +try-snowplow.com + +// SourceHut : https://sourcehut.org +// Submitted by Drew DeVault +srht.site + // Stackhero : https://www.stackhero.io // Submitted by Adrien Gillon stackhero-network.com +// Staclar : https://staclar.com +// Submitted by Matthias Merkel +novecore.site + // staticland : https://static.land // Submitted by Seth Vincent static.land dev.static.land sites.static.land +// Storebase : https://www.storebase.io +// Submitted by Tony Schirmer +storebase.store + +// Strategic System Consulting (eApps Hosting): https://www.eapps.com/ +// Submitted by Alex Oancea +vps-host.net +atl.jelastic.vps-host.net +njs.jelastic.vps-host.net +ric.jelastic.vps-host.net + // Sony Interactive Entertainment LLC : https://sie.com/ // Submitted by David Coles playstation-cloud.com @@ -12848,6 +13379,28 @@ // Submitted by Stefan Neufeind customer.speedpartner.de +// Spreadshop (sprd.net AG) : https://www.spreadshop.com/ +// Submitted by Martin Breest +myspreadshop.at +myspreadshop.com.au +myspreadshop.be +myspreadshop.ca +myspreadshop.ch +myspreadshop.com +myspreadshop.de +myspreadshop.dk +myspreadshop.es +myspreadshop.fi +myspreadshop.fr +myspreadshop.ie +myspreadshop.it +myspreadshop.net +myspreadshop.nl +myspreadshop.no +myspreadshop.pl +myspreadshop.se +myspreadshop.co.uk + // Standard Library : https://stdlib.com // Submitted by Jacob Lee api.stdlib.com @@ -12869,10 +13422,12 @@ // Submitted by Dan Miller temp-dns.com -// Swisscom Application Cloud: https://developer.swisscom.com -// Submitted by Matthias.Winzeler -applicationcloud.io -scapp.io +// Supabase : https://supabase.io +// Submitted by Inian Parameshwaran +supabase.co +supabase.in +supabase.net +su.paba.se // Symfony, SAS : https://symfony.com/ // Submitted by Fabien Potencier @@ -12901,10 +13456,19 @@ vpnplus.to direct.quickconnect.to +// Tabit Technologies Ltd. : https://tabit.cloud/ +// Submitted by Oren Agiv +tabitorder.co.il + // TAIFUN Software AG : http://taifun-software.de // Submitted by Bjoern Henke taifun-dns.de +// Tailscale Inc. : https://www.tailscale.com +// Submitted by David Anderson +beta.tailscale.net +ts.net + // TASK geographical domains (www.task.gda.pl/uslugi/dns) gda.pl gdansk.pl @@ -12928,22 +13492,42 @@ // Thingdust AG : https://thingdust.com/ // Submitted by Adrian Imboden +*.firenet.ch +*.svc.firenet.ch +reservd.com thingdustdata.com cust.dev.thingdust.io cust.disrec.thingdust.io cust.prod.thingdust.io cust.testing.thingdust.io +reservd.dev.thingdust.io +reservd.disrec.thingdust.io +reservd.testing.thingdust.io + +// ticket i/O GmbH : https://ticket.io +// Submitted by Christian Franke +tickets.io // Tlon.io : https://tlon.io // Submitted by Mark Staarink arvo.network azimuth.network +tlon.network + +// Tor Project, Inc. : https://torproject.org +// Submitted by Antoine Beaupré bloxcms.com townnews-staging.com +// TradableBits: https://tradablebits.com +// Submitted by Dmitry Khrisanov dmitry@tradablebits.com +tbits.me + // TrafficPlex GmbH : https://www.trafficplex.de/ // Submitted by Phillipp Röll 12hp.at @@ -13009,6 +13593,10 @@ virtualuser.de virtual-user.de +// Upli : https://upli.io +// Submitted by Lenny Bakkalian +upli.io + // urown.net : https://urown.net // Submitted by Hostmaster urown.cloud @@ -13022,6 +13610,12 @@ // Submitted by Danko Aleksejevs 2038.io +// Vercel, Inc : https://vercel.com/ +// Submitted by Connor Davis +vercel.app +vercel.dev +now.sh + // Viprinet Europe GmbH : http://www.viprinet.com // Submitted by Simon Kissel router.management @@ -13034,6 +13628,48 @@ // Submitted by Nathan van Bakel voorloper.cloud +// Voxel.sh DNS : https://voxel.sh/dns/ +// Submitted by Mia Rehlinger +neko.am +nyaa.am +be.ax +cat.ax +es.ax +eu.ax +gg.ax +mc.ax +us.ax +xy.ax +nl.ci +xx.gl +app.gp +blog.gt +de.gt +to.gt +be.gy +cc.hn +blog.kg +io.kg +jp.kg +tv.kg +uk.kg +us.kg +de.ls +at.md +de.md +jp.md +to.md +indie.porn +vxl.sh +ch.tc +me.tc +we.tc +nyan.to +at.vg +blog.vu +dev.vu +me.vu + // V.UA Domain Administrator : https://domain.v.ua/ // Submitted by Serhii Rostilo v.ua @@ -13042,10 +13678,26 @@ // Submitted by Masayuki Note wafflecell.com +// WapBlog.ID : https://www.wapblog.id +// Submitted by Fajar Sodik +idnblogger.com +indowapblog.com +bloger.id +wblog.id +wbq.me +fastblog.net + // WebHare bv: https://www.webhare.com/ // Submitted by Arnold Hendriks *.webhare.dev +// WebHotelier Technologies Ltd: https://www.webhotelier.net/ +// Submitted by Apostolos Tsakpinis +reserve-online.net +reserve-online.com +bookonline.app +hotelwithflight.com + // WeDeploy by Liferay, Inc. : https://www.wedeploy.com // Submitted by Henrique Vicente wedeploy.io @@ -13056,6 +13708,10 @@ // Submitted by Jung Jin remotewd.com +// WIARD Enterprises : https://wiardweb.com +// Submitted by Kidd Hustle +pages.wiardweb.com + // Wikimedia Labs : https://wikitech.wikimedia.org // Submitted by Arturo Borrero Gonzalez wmflabs.org @@ -13069,12 +13725,30 @@ // WoltLab GmbH : https://www.woltlab.com // Submitted by Tim Düsterhus +woltlab-demo.com myforum.community community-pro.de diskussionsbereich.de community-pro.net meinforum.net +// Woods Valldata : https://www.woodsvalldata.co.uk/ +// Submitted by Chris Whittle +affinitylottery.org.uk +raffleentry.org.uk +weeklylottery.org.uk + +// WP Engine : https://wpengine.com/ +// Submitted by Michael Smith +// Submitted by Brandon DuRette +wpenginepowered.com +js.wpenginepowered.com + +// Wix.com, Inc. : https://www.wix.com +// Submitted by Shahar Talmi +wixsite.com +editorx.io + // XenonCloud GbR: https://xenoncloud.net // Submitted by Julian Uphoff half.host @@ -13117,6 +13791,7 @@ // Yunohost : https://yunohost.org // Submitted by Valentin Grimaud +ynh.fr nohost.me noho.st @@ -13125,10 +13800,6 @@ za.net za.org -// Zeit, Inc. : https://zeit.domains/ -// Submitted by Olli Vanhoja -now.sh - // Zine EOOD : https://zine.bg/ // Submitted by Martin Angelov bss.design @@ -13139,8 +13810,4 @@ virtualserver.io enterprisecloud.nu -// Mintere : https://mintere.com/ -// Submitted by Ben Aubin -mintere.site - // ===END PRIVATE DOMAINS=== diff -Nru openjdk-17-17.0.3+7/make/data/publicsuffixlist/VERSION openjdk-17-17.0.4+8/make/data/publicsuffixlist/VERSION --- openjdk-17-17.0.3+7/make/data/publicsuffixlist/VERSION 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/publicsuffixlist/VERSION 2022-07-14 08:05:38.000000000 +0000 @@ -1,2 +1,2 @@ -Github: https://raw.githubusercontent.com/publicsuffix/list/cbbba1d234670453df9c930dfbf510c0474d4301/public_suffix_list.dat -Date: 2020-04-24 +Github: https://raw.githubusercontent.com/publicsuffix/list/3c213aab32b3c014f171b1673d4ce9b5cd72bf1c/public_suffix_list.dat +Date: 2021-11-27 diff -Nru openjdk-17-17.0.3+7/make/data/tzdata/africa openjdk-17-17.0.4+8/make/data/tzdata/africa --- openjdk-17-17.0.3+7/make/data/tzdata/africa 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/tzdata/africa 2022-07-14 08:05:38.000000000 +0000 @@ -941,6 +941,10 @@ # (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a)) # (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b))))) # (setq islamic-year (+ 1 islamic-year)))) +# +# From Milamber (2021-03-31, 2022-03-10), confirming these predictions: +# https://www.mmsp.gov.ma/fr/actualites.aspx?id=2076 +# https://www.ecoactu.ma/horaires-administration-ramadan-gmtheure-gmt-a-partir-de-dimanche-27-mars/ # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Morocco 1939 only - Sep 12 0:00 1:00 - diff -Nru openjdk-17-17.0.3+7/make/data/tzdata/asia openjdk-17-17.0.4+8/make/data/tzdata/asia --- openjdk-17-17.0.3+7/make/data/tzdata/asia 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/tzdata/asia 2022-07-14 08:05:38.000000000 +0000 @@ -3429,8 +3429,12 @@ # ... winter time will begin in Palestine from Friday 10-29, 01:00 AM # by 60 minutes backwards. # -# From Paul Eggert (2021-10-20): -# Guess future fall transitions on October's last Friday at 01:00. +# From Tim Parenti (2021-10-25), per Paul Eggert (2021-10-24): +# Guess future fall transitions at 01:00 on the Friday preceding October's +# last Sunday (i.e., Fri>=23), as this is more consistent with recent practice. + +# From Heba Hamad (2022-03-10): +# summer time will begin in Palestine from Sunday 03-27-2022, 00:00 AM. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -3466,9 +3470,10 @@ Rule Palestine 2016 2018 - Oct Sat>=24 1:00 0 - Rule Palestine 2019 only - Mar 29 0:00 1:00 S Rule Palestine 2019 only - Oct Sat>=24 0:00 0 - -Rule Palestine 2020 max - Mar Sat>=24 0:00 1:00 S +Rule Palestine 2020 2021 - Mar Sat>=24 0:00 1:00 S Rule Palestine 2020 only - Oct 24 1:00 0 - -Rule Palestine 2021 max - Oct lastFri 1:00 0 - +Rule Palestine 2021 max - Oct Fri>=23 1:00 0 - +Rule Palestine 2022 max - Mar Sun>=25 0:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct diff -Nru openjdk-17-17.0.3+7/make/data/tzdata/europe openjdk-17-17.0.4+8/make/data/tzdata/europe --- openjdk-17-17.0.3+7/make/data/tzdata/europe 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/tzdata/europe 2022-07-14 08:05:38.000000000 +0000 @@ -2808,8 +2808,26 @@ # says he remembers that Samara opted out of the 1992-01-19 exception # 2 days before the switch. # +# From Alois Treindl (2022-02-15): +# the Russian wikipedia page +# https://ru.wikipedia.org/wiki/Московское_время#Перемещение_границы_применения_московского_времени_на_восток +# contains the sentence (in Google translation) "In the autumn of +# 1981, Arkhangelsk, Vologda, Yaroslavl, Ivanovo, Vladimir, Ryazan, +# Lipetsk, Voronezh, Rostov-on-Don, Krasnodar and regions to the east +# of those named (about 30 in total) parted ways with Moscow time. +# However, the convenience of common time with Moscow turned out to be +# decisive - in 1982, these regions again switched to Moscow time." +# Shanks International atlas has similar information, and also the +# Russian book Zaitsev A., Kutalev D. A new astrologer's reference +# book. Coordinates of cities and time corrections, - The World of +# Urania, 2012 (Russian: Зайцев А., Куталёв Д., Новый справочник +# астролога. Координаты городов и временные поправки). +# To me it seems that an extra zone is needed, which starts with LMT +# util 1919, later follows Moscow since 1930, but deviates from it +# between 1 October 1981 until 1 April 1982. # -# From Paul Eggert (2016-03-18): +# +# From Paul Eggert (2022-02-15): # Given the above, we appear to be missing some Zone entries for the # chaotic early 1980s in Russia. It's not clear what these entries # should be. For now, sweep this under the rug and just document the @@ -2856,7 +2874,7 @@ 1:00 C-Eur CE%sT 1944 Apr 13 3:00 Russia MSK/MSD 1990 3:00 - MSK 1990 Jul 1 2:00 - 2:00 - EET 1992 + 2:00 - EET 1992 Mar 20 # Central Crimea used Moscow time 1994/1997. # # From Paul Eggert (2006-03-22): @@ -2866,7 +2884,7 @@ # sometime between the 1994 DST switches. Shanks & Pottenger simply say # 1994-09-25 03:00, but that can't be right. For now, guess it # changed in May. - 2:00 E-Eur EE%sT 1994 May + 2:00 C-Eur EE%sT 1994 May # From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev. 3:00 E-Eur MSK/MSD 1996 Mar 31 0:00s 3:00 1:00 MSD 1996 Oct 27 3:00s @@ -4033,6 +4051,27 @@ # Ukraine # +# From Alois Triendl (2014-03-01): +# REGULATION A N O V A on March 20, 1992 N 139 ... means that from +# 1992 on, Ukraine had DST with begin time at 02:00 am, on last Sunday +# in March, and end time 03:00 am, last Sunday in September.... +# CABINET OF MINISTERS OF UKRAINE RESOLUTION on May 13, 1996 N 509 +# "On the order of computation time on the territory of Ukraine" .... +# As this cabinet decision is from May 1996, it seems likely that the +# transition in March 1996, which predates it, was still at 2:00 am +# and not at 3:00 as would have been under EU rules. +# This is why I have set the change to EU rules into May 1996, +# so that the change in March is stil covered by the Ukraine rule. +# The next change in October 1996 happened under EU rules.... +# TZ database holds three other zones for Ukraine.... I have not yet +# worked out the consequences for these three zones, as we (me and my +# US colleague David Cochrane) are still trying to get more +# information upon these local deviations from Kiev rules. +# +# From Paul Eggert (2022-02-08): +# For now, assume that Ukraine's other three zones followed the same rules, +# except that Crimea switched to Moscow time in 1994 as described elsewhere. + # From Igor Karpov, who works for the Ukrainian Ministry of Justice, # via Garrett Wollman (2003-01-27): # BTW, I've found the official document on this matter. It's government @@ -4122,7 +4161,7 @@ 1:00 C-Eur CE%sT 1943 Nov 6 3:00 Russia MSK/MSD 1990 Jul 1 2:00 2:00 1:00 EEST 1991 Sep 29 3:00 - 2:00 E-Eur EE%sT 1995 + 2:00 C-Eur EE%sT 1996 May 13 2:00 EU EE%sT # Transcarpathia used CET 1990/1991. # "Uzhhorod" is the transliteration of the Rusyn/Ukrainian pronunciation, but @@ -4135,8 +4174,8 @@ 3:00 Russia MSK/MSD 1990 3:00 - MSK 1990 Jul 1 2:00 1:00 - CET 1991 Mar 31 3:00 - 2:00 - EET 1992 - 2:00 E-Eur EE%sT 1995 + 2:00 - EET 1992 Mar 20 + 2:00 C-Eur EE%sT 1996 May 13 2:00 EU EE%sT # Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991. # "Zaporizhia" is the transliteration of the Ukrainian name, but @@ -4149,7 +4188,8 @@ 3:00 - MSK 1941 Aug 25 1:00 C-Eur CE%sT 1943 Oct 25 3:00 Russia MSK/MSD 1991 Mar 31 2:00 - 2:00 E-Eur EE%sT 1995 + 2:00 E-Eur EE%sT 1992 Mar 20 + 2:00 C-Eur EE%sT 1996 May 13 2:00 EU EE%sT # Vatican City diff -Nru openjdk-17-17.0.3+7/make/data/tzdata/leapseconds openjdk-17-17.0.4+8/make/data/tzdata/leapseconds --- openjdk-17-17.0.3+7/make/data/tzdata/leapseconds 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/tzdata/leapseconds 2022-07-14 08:05:38.000000000 +0000 @@ -95,11 +95,11 @@ # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2022 Jun 28 00:00:00 +#Expires 2022 Dec 28 00:00:00 # POSIX timestamps for the data in this file: #updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1656374400 (2022-06-28 00:00:00 UTC) +#expires 1672185600 (2022-12-28 00:00:00 UTC) -# Updated through IERS Bulletin C62 -# File expires on: 28 June 2022 +# Updated through IERS Bulletin C63 +# File expires on: 28 December 2022 diff -Nru openjdk-17-17.0.3+7/make/data/tzdata/southamerica openjdk-17-17.0.4+8/make/data/tzdata/southamerica --- openjdk-17-17.0.3+7/make/data/tzdata/southamerica 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/tzdata/southamerica 2022-07-14 08:05:38.000000000 +0000 @@ -1109,7 +1109,7 @@ # Chile -# From Paul Eggert (2015-04-03): +# From Paul Eggert (2022-03-15): # Shanks & Pottenger says America/Santiago introduced standard time in # 1890 and rounds its UT offset to 70W40; guess that in practice this # was the same offset as in 1916-1919. It also says Pacific/Easter @@ -1132,7 +1132,7 @@ # Historia de la hora oficial de Chile (retrieved 2012-10-24). See: # https://web.archive.org/web/20121024234627/http://www.horaoficial.cl/horaof.htm # A fancier Spanish version (requiring mouse-clicking) is at: -# http://www.horaoficial.cl/historia_hora.html +# http://www.horaoficial.cl/historia_hora.php # Conflicts between [1] and [2] were resolved as follows: # # - [1] says the 1910 transition was Jan 1, [2] says Jan 10 and cites @@ -1141,7 +1141,8 @@ # - [1] says SMT was -4:42:45, [2] says Chile's official time from # 1916 to 1919 was -4:42:46.3, the meridian of Chile's National # Astronomical Observatory (OAN), then located in what is now -# Quinta Normal in Santiago. Go with [2], rounding it to -4:42:46. +# Quinta Normal in Santiago. Go with [1], as this matches the meridian +# referred to by the relevant Chilean laws to this day. # # - [1] says the 1918 transition was Sep 1, [2] says Sep 10 and cites # Boletín No. 22, Aviso No. 129/1918 (1918-08-23). Go with [2]. @@ -1163,6 +1164,32 @@ # this is known to work for DST transitions starting in 2008 and # may well be true for earlier transitions. +# From Tim Parenti (2022-03-15): +# For a brief period of roughly six weeks in 1946, DST was only observed on an +# emergency basis in specific regions of central Chile; namely, "the national +# territory between the provinces of Coquimbo and Concepción, inclusive". +# This was enacted by Decree 3,891, dated 1946-07-13, and took effect +# 1946-07-14 24:00, advancing these central regions to -03. +# https://www.diariooficial.interior.gob.cl/versiones-anteriores/do-h/19460715/#page/1 +# The decree contemplated "[t]hat this advancement of the Official Time, even +# though it has been proposed for the cities of Santiago and Valparaíso only, +# must be agreed with that of other cities, due to the connection of various +# activities that require it, such as, for example, the operation of rail +# services". It was originally set to expire after 30 days but was extended +# through 1946-08-31 by Decree 4,506, dated 1946-08-13. +# https://www.diariooficial.interior.gob.cl/versiones-anteriores/do-h/19460814/#page/1 +# +# Law Number 8,522, promulgated 1946-08-27, reunified Chilean clocks at their +# new "Summer Time" of -04, reckoned as that of "the meridian of the +# Astronomical Observatory of Lo Espejo, advanced by 42 minutes and 45 +# seconds". +# https://www.diariooficial.interior.gob.cl/versiones-anteriores/do-h/19460828/#page/1 +# After a brief "Winter Time" stint at -05 beginning 1947-04-01, Law Number +# 8,777, promulgated 1947-05-17, established year-round -04 "from 23:00 on the +# second day after it is published in the 'Diario Oficial'." It was published +# on Monday 1947-05-19 and so took effect from Wednesday 1947-05-21 23:00. +# https://www.diariooficial.interior.gob.cl/versiones-anteriores/do-h/19470519/#page/1 + # From Eduardo Krell (1995-10-19): # The law says to switch to DST at midnight [24:00] on the second SATURDAY # of October.... The law is the same for March and October. @@ -1321,12 +1348,12 @@ # IATA SSIM anomalies: (1992-02) says 1992-03-14; # (1996-09) says 1998-03-08. Ignore these. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Santiago -4:42:46 - LMT 1890 - -4:42:46 - SMT 1910 Jan 10 # Santiago Mean Time +Zone America/Santiago -4:42:45 - LMT 1890 + -4:42:45 - SMT 1910 Jan 10 # Santiago Mean Time -5:00 - -05 1916 Jul 1 - -4:42:46 - SMT 1918 Sep 10 + -4:42:45 - SMT 1918 Sep 10 -4:00 - -04 1919 Jul 1 - -4:42:46 - SMT 1927 Sep 1 + -4:42:45 - SMT 1927 Sep 1 -5:00 Chile -05/-04 1932 Sep 1 -4:00 - -04 1942 Jun 1 -5:00 - -05 1942 Aug 1 @@ -1336,11 +1363,11 @@ -5:00 - -05 1947 May 21 23:00 -4:00 Chile -04/-03 Zone America/Punta_Arenas -4:43:40 - LMT 1890 - -4:42:46 - SMT 1910 Jan 10 + -4:42:45 - SMT 1910 Jan 10 -5:00 - -05 1916 Jul 1 - -4:42:46 - SMT 1918 Sep 10 + -4:42:45 - SMT 1918 Sep 10 -4:00 - -04 1919 Jul 1 - -4:42:46 - SMT 1927 Sep 1 + -4:42:45 - SMT 1927 Sep 1 -5:00 Chile -05/-04 1932 Sep 1 -4:00 - -04 1942 Jun 1 -5:00 - -05 1942 Aug 1 diff -Nru openjdk-17-17.0.3+7/make/data/tzdata/VERSION openjdk-17-17.0.4+8/make/data/tzdata/VERSION --- openjdk-17-17.0.3+7/make/data/tzdata/VERSION 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/data/tzdata/VERSION 2022-07-14 08:05:38.000000000 +0000 @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2021e +tzdata2022a diff -Nru openjdk-17-17.0.3+7/make/hotspot/gensrc/GensrcAdlc.gmk openjdk-17-17.0.4+8/make/hotspot/gensrc/GensrcAdlc.gmk --- openjdk-17-17.0.3+7/make/hotspot/gensrc/GensrcAdlc.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/hotspot/gensrc/GensrcAdlc.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -58,6 +58,9 @@ ADLC_CFLAGS += -I$(TOPDIR)/src/hotspot/share + # Add file macro mappings + ADLC_CFLAGS += $(FILE_MACRO_CFLAGS) + $(eval $(call SetupNativeCompilation, BUILD_ADLC, \ NAME := adlc, \ TYPE := EXECUTABLE, \ diff -Nru openjdk-17-17.0.3+7/make/InitSupport.gmk openjdk-17-17.0.4+8/make/InitSupport.gmk --- openjdk-17-17.0.3+7/make/InitSupport.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/InitSupport.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -313,6 +313,15 @@ SOURCE_DATE := $$(shell $$(DATE) +"%s") endif export SOURCE_DATE_EPOCH := $$(SOURCE_DATE) + ifeq ($$(IS_GNU_DATE), yes) + export SOURCE_DATE_ISO_8601 := $$(shell $$(DATE) --utc \ + --date="@$$(SOURCE_DATE_EPOCH)" \ + +"%Y-%m-%dT%H:%M:%SZ" 2> /dev/null) + else + export SOURCE_DATE_ISO_8601 := $$(shell $$(DATE) -u \ + -j -f "%s" "$$(SOURCE_DATE_EPOCH)" \ + +"%Y-%m-%dT%H:%M:%SZ" 2> /dev/null) + endif endef # Parse COMPARE_BUILD into COMPARE_BUILD_* diff -Nru openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java --- openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java 2022-07-14 08:05:38.000000000 +0000 @@ -114,6 +114,7 @@ ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT); private static Set AVAILABLE_TZIDS; + static int copyrightYear; private static String zoneNameTempFile; private static String tzDataDir; private static final Map canonicalTZMap = new HashMap<>(); @@ -217,6 +218,10 @@ verbose = true; break; + case "-year": + copyrightYear = Integer.parseInt(args[++i]); + break; + case "-zntempfile": zoneNameTempFile = args[++i]; break; @@ -235,7 +240,7 @@ } } } catch (RuntimeException e) { - severe("unknown or imcomplete arg(s): " + currentArg); + severe("unknown or incomplete arg(s): " + currentArg); usage(); System.exit(1); } @@ -260,6 +265,10 @@ setupBaseLocales("en-US"); } + if (copyrightYear == 0) { + copyrightYear = ZonedDateTime.now(ZoneId.of("America/Los_Angeles")).getYear(); + } + bundleGenerator = new ResourceBundleGenerator(); // Parse data independent of locales @@ -292,6 +301,7 @@ + "\t-basemodule generates bundles that go into java.base module%n" + "\t-baselocales loc(,loc)* locales that go into the base module%n" + "\t-o dir output directory (default: ./build/gensrc)%n" + + "\t-year year copyright year in output%n" + "\t-zntempfile template file for java.time.format.ZoneName.java%n" + "\t-tzdatadir tzdata directory for java.time.format.ZoneName.java%n" + "\t-utf8 use UTF-8 rather than \\uxxxx (for debug)%n"); diff -Nru openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/cldrconverter/CopyrightHeaders.java openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/cldrconverter/CopyrightHeaders.java --- openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/cldrconverter/CopyrightHeaders.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/cldrconverter/CopyrightHeaders.java 2022-07-14 08:05:38.000000000 +0000 @@ -26,6 +26,7 @@ package build.tools.cldrconverter; import java.util.Calendar; +import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; @@ -131,8 +132,7 @@ " * questions.\n" + " */\n"; - static String getOracleCopyright() { - int year = getYear(); + static String getOracleCopyright(int year) { return String.format(year > 2012 ? ORACLE_AFTER2012 : ORACLE2012, year); } @@ -140,16 +140,10 @@ return UNICODE; } - static String getOpenJDKCopyright() { - int year = getYear(); + static String getOpenJDKCopyright(int year) { return String.format(year > 2012 ? OPENJDK_AFTER2012 : OPENJDK2012, year); } - private static int getYear() { - return new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"), - Locale.US).get(Calendar.YEAR); - } - // no instantiation private CopyrightHeaders() { } diff -Nru openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java --- openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java 2022-07-14 08:05:38.000000000 +0000 @@ -198,7 +198,7 @@ try (PrintWriter out = new PrintWriter(file, encoding)) { // Output copyright headers - out.println(CopyrightHeaders.getOpenJDKCopyright()); + out.println(CopyrightHeaders.getOpenJDKCopyright(CLDRConverter.copyrightYear)); out.println(CopyrightHeaders.getUnicodeCopyright()); if (useJava) { @@ -266,7 +266,7 @@ CLDRConverter.info("Generating file " + file); try (PrintWriter out = new PrintWriter(file, "us-ascii")) { - out.printf(CopyrightHeaders.getOpenJDKCopyright()); + out.printf(CopyrightHeaders.getOpenJDKCopyright(CLDRConverter.copyrightYear)); out.printf((CLDRConverter.isBaseModule ? "package sun.util.cldr;\n\n" : "package sun.util.resources.cldr.provider;\n\n") diff -Nru openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java --- openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/generatelsrequivmaps/EquivMapsGenerator.java 2022-07-14 08:05:38.000000000 +0000 @@ -30,13 +30,15 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; -import java.time.ZoneId; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.TimeZone; import java.util.TreeMap; import java.util.stream.Collectors; @@ -52,17 +54,19 @@ public class EquivMapsGenerator { public static void main(String[] args) throws Exception { - if (args.length != 2) { + if (args.length != 3) { System.err.println("Usage: java EquivMapsGenerator" - + " language-subtag-registry.txt LocaleEquivalentMaps.java"); + + " language-subtag-registry.txt LocaleEquivalentMaps.java copyrightYear"); System.exit(1); } + copyrightYear = Integer.parseInt(args[2]); readLSRfile(args[0]); generateEquivalentMap(); generateSourceCode(args[1]); } private static String LSRrevisionDate; + private static int copyrightYear; private static Map initialLanguageMap = new TreeMap<>(); private static Map initialRegionVariantMap = @@ -246,9 +250,7 @@ + "}"; private static String getOpenJDKCopyright() { - int year = ZonedDateTime.now(ZoneId - .of("America/Los_Angeles")).getYear(); - return String.format(Locale.US, COPYRIGHT, year); + return String.format(Locale.US, COPYRIGHT, copyrightYear); } /** diff -Nru openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/makezipreproducible/MakeZipReproducible.java openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/makezipreproducible/MakeZipReproducible.java --- openjdk-17-17.0.3+7/make/jdk/src/classes/build/tools/makezipreproducible/MakeZipReproducible.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/jdk/src/classes/build/tools/makezipreproducible/MakeZipReproducible.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * 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,18 +34,22 @@ import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.LocalDateTime; /** * Generate a zip file in a "reproducible" manner from the input zip file. * Standard zip tools rely on OS file list querying whose ordering can vary * by platform architecture, this class ensures the zip entries are ordered - * and also supports SOURCE_DATE_EPOCH timestamps. + * and also supports SOURCE_DATE_EPOCH timestamps which will set the ZipEntry + * local time in UTC. */ public class MakeZipReproducible { String input_file = null; String fname = null; String zname = ""; - long timestamp = -1L; + LocalDateTime timestamp = null; boolean verbose = false; // Keep a sorted Set of ZipEntrys to be processed, so that the zip is reproducible @@ -117,7 +121,9 @@ break; case 't': // SOURCE_DATE_EPOCH timestamp specified - timestamp = Long.parseLong(args[++count]) * 1000; + long epochSeconds = Long.parseLong(args[++count]); + Instant instant = Instant.ofEpochSecond(epochSeconds); + timestamp = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); break; case 'v': verbose = true; @@ -194,10 +200,14 @@ } // Set to specified timestamp if set otherwise leave as original lastModified time - if (timestamp != -1L) { - entry.setTime(timestamp); + if (timestamp != null) { + entry.setTimeLocal(timestamp); } + // Ensure "extra" field is not set from original ZipEntry info that may be not deterministic + // eg.may contain specific UID/GID + entry.setExtra(null); + zos.putNextEntry(entry); if (entry.getSize() > 0 && entryInputStream != null) { entryInputStream.transferTo(zos); diff -Nru openjdk-17-17.0.3+7/make/modules/java.base/Gensrc.gmk openjdk-17-17.0.4+8/make/modules/java.base/Gensrc.gmk --- openjdk-17-17.0.3+7/make/modules/java.base/Gensrc.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/modules/java.base/Gensrc.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -62,6 +62,7 @@ -baselocales "en-US" \ -o $(GENSRC_DIR) \ -basemodule \ + -year $(COPYRIGHT_YEAR) \ -zntempfile $(ZONENAME_TEMPLATE) \ -tzdatadir $(TZ_DATA_DIR)) $(TOUCH) $@ @@ -99,7 +100,7 @@ $(GENSRC_LSREQUIVMAPS): $(TOPDIR)/make/data/lsrdata/language-subtag-registry.txt $(BUILD_TOOLS_JDK) $(call MakeDir, $(@D)) - $(TOOL_GENERATELSREQUIVMAPS) $< $@ + $(TOOL_GENERATELSREQUIVMAPS) $< $@ $(COPYRIGHT_YEAR) TARGETS += $(GENSRC_LSREQUIVMAPS) diff -Nru openjdk-17-17.0.3+7/make/modules/java.desktop/lib/Awt2dLibraries.gmk openjdk-17-17.0.4+8/make/modules/java.desktop/lib/Awt2dLibraries.gmk --- openjdk-17-17.0.3+7/make/modules/java.desktop/lib/Awt2dLibraries.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/modules/java.desktop/lib/Awt2dLibraries.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -470,7 +470,6 @@ endif - LIBFONTMANAGER_EXTRA_HEADER_DIRS := \ libharfbuzz \ common/awt \ @@ -485,6 +484,14 @@ LIBFONTMANAGER_OPTIMIZATION := HIGHEST +ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), ) + # gcc (and to an extent clang) is particularly bad at optimizing these files, + # causing a massive spike in compile time. We don't care about these + # particular files anyway, so lower optimization level. + BUILD_LIBFONTMANAGER_hb-subset.cc_OPTIMIZATION := SIZE + BUILD_LIBFONTMANAGER_hb-subset-plan.cc_OPTIMIZATION := SIZE +endif + ifeq ($(call isTargetOs, windows), true) LIBFONTMANAGER_EXCLUDE_FILES += X11FontScaler.c \ X11TextRenderer.c diff -Nru openjdk-17-17.0.3+7/make/modules/jdk.localedata/Gensrc.gmk openjdk-17-17.0.4+8/make/modules/jdk.localedata/Gensrc.gmk --- openjdk-17-17.0.3+7/make/modules/jdk.localedata/Gensrc.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/modules/jdk.localedata/Gensrc.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -46,6 +46,7 @@ $(call ExecuteWithLog, $@, \ $(TOOL_CLDRCONVERTER) -base $(CLDR_DATA_DIR) \ -baselocales "en-US" \ + -year $(COPYRIGHT_YEAR) \ -o $(GENSRC_DIR)) $(TOUCH) $@ diff -Nru openjdk-17-17.0.3+7/make/TestImage.gmk openjdk-17-17.0.4+8/make/TestImage.gmk --- openjdk-17-17.0.3+7/make/TestImage.gmk 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/make/TestImage.gmk 2022-07-14 08:05:38.000000000 +0000 @@ -35,8 +35,8 @@ $(BUILD_INFO_PROPERTIES): $(call MakeTargetDir) $(ECHO) "# Build info properties for JDK tests" > $@ - $(ECHO) "build.workspace.root=$(call FixPath, $(WORKSPACE_ROOT))" >> $@ - $(ECHO) "build.output.root=$(call FixPath, $(OUTPUTDIR))" >> $@ + $(ECHO) 'build.workspace.root=$(call FixPath, $(WORKSPACE_ROOT))' >> $@ + $(ECHO) 'build.output.root=$(call FixPath, $(OUTPUTDIR))' >> $@ README := $(TEST_IMAGE_DIR)/Readme.txt diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/aarch64/immediate_aarch64.cpp openjdk-17-17.0.4+8/src/hotspot/cpu/aarch64/immediate_aarch64.cpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/aarch64/immediate_aarch64.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/aarch64/immediate_aarch64.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -129,8 +129,17 @@ uint64_t replicate(uint64_t bits, int nbits, int count) { + assert(count > 0, "must be"); + assert(nbits > 0, "must be"); + assert(count * nbits <= 64, "must be"); + + // Special case nbits == 64 since the shift below with that nbits value + // would result in undefined behavior. + if (nbits == 64) { + return bits; + } + uint64_t result = 0; - // nbits may be 64 in which case we want mask to be -1 uint64_t mask = ones(nbits); for (int i = 0; i < count ; i++) { result <<= nbits; diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp openjdk-17-17.0.4+8/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -5103,18 +5103,6 @@ return entry; } - // code for comparing 16 bytes of strings with same encoding - void compare_string_16_bytes_same(Label &DIFF1, Label &DIFF2) { - Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, tmp1 = r10, tmp2 = r11; - __ ldr(rscratch1, Address(__ post(str1, 8))); - __ eor(rscratch2, tmp1, tmp2); - __ ldr(cnt1, Address(__ post(str2, 8))); - __ cbnz(rscratch2, DIFF1); - __ ldr(tmp1, Address(__ post(str1, 8))); - __ eor(rscratch2, rscratch1, cnt1); - __ ldr(tmp2, Address(__ post(str2, 8))); - __ cbnz(rscratch2, DIFF2); - } // code for comparing 16 characters of strings with Latin1 and Utf16 encoding void compare_string_16_x_LU(Register tmpL, Register tmpU, Label &DIFF1, @@ -5321,97 +5309,108 @@ : "compare_long_string_same_encoding UU"); address entry = __ pc(); Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, cnt2 = r4, - tmp1 = r10, tmp2 = r11; - Label SMALL_LOOP, LARGE_LOOP_PREFETCH, CHECK_LAST, DIFF2, TAIL, - LENGTH_DIFF, DIFF, LAST_CHECK_AND_LENGTH_DIFF, - DIFF_LAST_POSITION, DIFF_LAST_POSITION2; + tmp1 = r10, tmp2 = r11, tmp1h = rscratch1, tmp2h = rscratch2; + + Label LARGE_LOOP_PREFETCH, LOOP_COMPARE16, DIFF, LESS16, LESS8, CAL_DIFFERENCE, LENGTH_DIFF; + // exit from large loop when less than 64 bytes left to read or we're about // to prefetch memory behind array border int largeLoopExitCondition = MAX2(64, SoftwarePrefetchHintDistance)/(isLL ? 1 : 2); - // cnt1/cnt2 contains amount of characters to compare. cnt1 can be re-used - // update cnt2 counter with already loaded 8 bytes + + // before jumping to stub, pre-load 8 bytes already, so do comparison directly + __ eor(rscratch2, tmp1, tmp2); + __ cbnz(rscratch2, CAL_DIFFERENCE); + __ sub(cnt2, cnt2, wordSize/(isLL ? 1 : 2)); // update pointers, because of previous read __ add(str1, str1, wordSize); __ add(str2, str2, wordSize); if (SoftwarePrefetchHintDistance >= 0) { + __ align(OptoLoopAlignment); __ bind(LARGE_LOOP_PREFETCH); __ prfm(Address(str1, SoftwarePrefetchHintDistance)); __ prfm(Address(str2, SoftwarePrefetchHintDistance)); - compare_string_16_bytes_same(DIFF, DIFF2); - compare_string_16_bytes_same(DIFF, DIFF2); + + for (int i = 0; i < 4; i++) { + __ ldp(tmp1, tmp1h, Address(str1, i * 16)); + __ ldp(tmp2, tmp2h, Address(str2, i * 16)); + __ cmp(tmp1, tmp2); + __ ccmp(tmp1h, tmp2h, 0, Assembler::EQ); + __ br(Assembler::NE, DIFF); + } __ sub(cnt2, cnt2, isLL ? 64 : 32); - compare_string_16_bytes_same(DIFF, DIFF2); + __ add(str1, str1, 64); + __ add(str2, str2, 64); __ subs(rscratch2, cnt2, largeLoopExitCondition); - compare_string_16_bytes_same(DIFF, DIFF2); - __ br(__ GT, LARGE_LOOP_PREFETCH); - __ cbz(cnt2, LAST_CHECK_AND_LENGTH_DIFF); // no more chars left? + __ br(Assembler::GE, LARGE_LOOP_PREFETCH); + __ cbz(cnt2, LENGTH_DIFF); // no more chars left? } - // less than 16 bytes left? - __ subs(cnt2, cnt2, isLL ? 16 : 8); - __ br(__ LT, TAIL); + + __ subs(rscratch1, cnt2, isLL ? 16 : 8); + __ br(Assembler::LE, LESS16); __ align(OptoLoopAlignment); - __ bind(SMALL_LOOP); - compare_string_16_bytes_same(DIFF, DIFF2); - __ subs(cnt2, cnt2, isLL ? 16 : 8); - __ br(__ GE, SMALL_LOOP); - __ bind(TAIL); - __ adds(cnt2, cnt2, isLL ? 16 : 8); - __ br(__ EQ, LAST_CHECK_AND_LENGTH_DIFF); + __ bind(LOOP_COMPARE16); + __ ldp(tmp1, tmp1h, Address(__ post(str1, 16))); + __ ldp(tmp2, tmp2h, Address(__ post(str2, 16))); + __ cmp(tmp1, tmp2); + __ ccmp(tmp1h, tmp2h, 0, Assembler::EQ); + __ br(Assembler::NE, DIFF); + __ sub(cnt2, cnt2, isLL ? 16 : 8); + __ subs(rscratch2, cnt2, isLL ? 16 : 8); + __ br(Assembler::LT, LESS16); + + __ ldp(tmp1, tmp1h, Address(__ post(str1, 16))); + __ ldp(tmp2, tmp2h, Address(__ post(str2, 16))); + __ cmp(tmp1, tmp2); + __ ccmp(tmp1h, tmp2h, 0, Assembler::EQ); + __ br(Assembler::NE, DIFF); + __ sub(cnt2, cnt2, isLL ? 16 : 8); + __ subs(rscratch2, cnt2, isLL ? 16 : 8); + __ br(Assembler::GE, LOOP_COMPARE16); + __ cbz(cnt2, LENGTH_DIFF); + + __ bind(LESS16); + // each 8 compare __ subs(cnt2, cnt2, isLL ? 8 : 4); - __ br(__ LE, CHECK_LAST); - __ eor(rscratch2, tmp1, tmp2); - __ cbnz(rscratch2, DIFF); + __ br(Assembler::LE, LESS8); __ ldr(tmp1, Address(__ post(str1, 8))); __ ldr(tmp2, Address(__ post(str2, 8))); + __ eor(rscratch2, tmp1, tmp2); + __ cbnz(rscratch2, CAL_DIFFERENCE); __ sub(cnt2, cnt2, isLL ? 8 : 4); - __ bind(CHECK_LAST); + + __ bind(LESS8); // directly load last 8 bytes if (!isLL) { - __ add(cnt2, cnt2, cnt2); // now in bytes + __ add(cnt2, cnt2, cnt2); } + __ ldr(tmp1, Address(str1, cnt2)); + __ ldr(tmp2, Address(str2, cnt2)); __ eor(rscratch2, tmp1, tmp2); - __ cbnz(rscratch2, DIFF); - __ ldr(rscratch1, Address(str1, cnt2)); - __ ldr(cnt1, Address(str2, cnt2)); - __ eor(rscratch2, rscratch1, cnt1); __ cbz(rscratch2, LENGTH_DIFF); - // Find the first different characters in the longwords and - // compute their difference. - __ bind(DIFF2); - __ rev(rscratch2, rscratch2); - __ clz(rscratch2, rscratch2); - __ andr(rscratch2, rscratch2, isLL ? -8 : -16); - __ lsrv(rscratch1, rscratch1, rscratch2); - if (isLL) { - __ lsrv(cnt1, cnt1, rscratch2); - __ uxtbw(rscratch1, rscratch1); - __ uxtbw(cnt1, cnt1); - } else { - __ lsrv(cnt1, cnt1, rscratch2); - __ uxthw(rscratch1, rscratch1); - __ uxthw(cnt1, cnt1); - } - __ subw(result, rscratch1, cnt1); - __ b(LENGTH_DIFF); + __ b(CAL_DIFFERENCE); + __ bind(DIFF); + __ cmp(tmp1, tmp2); + __ csel(tmp1, tmp1, tmp1h, Assembler::NE); + __ csel(tmp2, tmp2, tmp2h, Assembler::NE); + // reuse rscratch2 register for the result of eor instruction + __ eor(rscratch2, tmp1, tmp2); + + __ bind(CAL_DIFFERENCE); __ rev(rscratch2, rscratch2); __ clz(rscratch2, rscratch2); __ andr(rscratch2, rscratch2, isLL ? -8 : -16); __ lsrv(tmp1, tmp1, rscratch2); + __ lsrv(tmp2, tmp2, rscratch2); if (isLL) { - __ lsrv(tmp2, tmp2, rscratch2); __ uxtbw(tmp1, tmp1); __ uxtbw(tmp2, tmp2); } else { - __ lsrv(tmp2, tmp2, rscratch2); __ uxthw(tmp1, tmp1); __ uxthw(tmp2, tmp2); } __ subw(result, tmp1, tmp2); - __ b(LENGTH_DIFF); - __ bind(LAST_CHECK_AND_LENGTH_DIFF); - __ eor(rscratch2, tmp1, tmp2); - __ cbnz(rscratch2, DIFF); + __ bind(LENGTH_DIFF); __ ret(lr); return entry; diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp openjdk-17-17.0.4+8/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2021 SAP SE. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022 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 @@ -2942,16 +2942,17 @@ // Store a non-null value into the box. std(box, BasicLock::displaced_header_offset_in_bytes(), box); + beq(flag, cont); -# ifdef ASSERT + // Check for recursive locking. + cmpd(flag, current_header, R16_thread); bne(flag, cont); - // We have acquired the monitor, check some invariants. - addi(/*monitor=*/temp, temp, -ObjectMonitor::owner_offset_in_bytes()); - // Invariant 1: _recursions should be 0. - //assert(ObjectMonitor::recursions_size_in_bytes() == 8, "unexpected size"); - asm_assert_mem8_is_zero(ObjectMonitor::recursions_offset_in_bytes(), temp, - "monitor->_recursions should be 0"); -# endif + + // Current thread already owns the lock. Just increment recursions. + Register recursions = displaced_header; + ld(recursions, ObjectMonitor::recursions_offset_in_bytes()-ObjectMonitor::owner_offset_in_bytes(), temp); + addi(recursions, recursions, 1); + std(recursions, ObjectMonitor::recursions_offset_in_bytes()-ObjectMonitor::owner_offset_in_bytes(), temp); #if INCLUDE_RTM_OPT } // use_rtm() @@ -2967,8 +2968,7 @@ bool try_bias, bool use_rtm) { assert_different_registers(oop, box, temp, displaced_header, current_header); assert(flag != CCR0, "bad condition register"); - Label cont; - Label object_has_monitor; + Label cont, object_has_monitor, notRecursive; if (try_bias) { biased_locking_exit(flag, oop, current_header, cont); @@ -3039,11 +3039,16 @@ #endif ld(displaced_header, ObjectMonitor::recursions_offset_in_bytes(), current_header); - xorr(temp, R16_thread, temp); // Will be 0 if we are the owner. - orr(temp, temp, displaced_header); // Will be 0 if there are 0 recursions. - cmpdi(flag, temp, 0); + + cmpd(flag, temp, R16_thread); bne(flag, cont); + addic_(displaced_header, displaced_header, -1); + blt(CCR0, notRecursive); // Not recursive if negative after decrement. + std(displaced_header, ObjectMonitor::recursions_offset_in_bytes(), current_header); + b(cont); // flag is already EQ here. + + bind(notRecursive); ld(temp, ObjectMonitor::EntryList_offset_in_bytes(), current_header); ld(displaced_header, ObjectMonitor::cxq_offset_in_bytes(), current_header); orr(temp, temp, displaced_header); // Will be 0 if both are 0. diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp openjdk-17-17.0.4+8/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2021 SAP SE. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022 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 @@ -4616,8 +4616,6 @@ public: StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { - // replace the standard masm with a special one: - _masm = new MacroAssembler(code); if (all) { generate_all(); } else { diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/s390/stubGenerator_s390.cpp openjdk-17-17.0.4+8/src/hotspot/cpu/s390/stubGenerator_s390.cpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/s390/stubGenerator_s390.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/s390/stubGenerator_s390.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2019 SAP SE. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022 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 @@ -2404,9 +2404,6 @@ public: StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { - // Replace the standard masm with a special one: - _masm = new MacroAssembler(code); - _stub_count = !all ? 0x100 : 0x200; if (all) { generate_all(); diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/x86/assembler_x86.cpp openjdk-17-17.0.4+8/src/hotspot/cpu/x86/assembler_x86.cpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/x86/assembler_x86.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/x86/assembler_x86.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -7328,6 +7328,9 @@ void Assembler::vpxor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + vector_len == AVX_256bit ? VM_Version::supports_avx2() : + vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0xEF, (0xC0 | encode)); @@ -7335,6 +7338,9 @@ void Assembler::vpxor(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + vector_len == AVX_256bit ? VM_Version::supports_avx2() : + vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); @@ -7947,12 +7953,12 @@ void Assembler::evbroadcasti32x4(XMMRegister dst, Address src, int vector_len) { assert(vector_len != Assembler::AVX_128bit, ""); - assert(VM_Version::supports_avx512dq(), ""); + assert(VM_Version::supports_evex(), ""); assert(dst != xnoreg, "sanity"); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_rex_vex_w_reverted(); - attributes.set_address_attributes(/* tuple_type */ EVEX_T2, /* input_size_in_bits */ EVEX_64bit); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); // swap src<->dst for encoding vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x5A); diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp openjdk-17-17.0.4+8/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -452,7 +452,7 @@ void opmask_register_save(KRegister reg) { _spill_offset -= 8; - __ kmovql(Address(rsp, _spill_offset), reg); + __ kmov(Address(rsp, _spill_offset), reg); } void gp_register_restore(Register reg) { @@ -461,7 +461,7 @@ } void opmask_register_restore(KRegister reg) { - __ kmovql(reg, Address(rsp, _spill_offset)); + __ kmov(reg, Address(rsp, _spill_offset)); _spill_offset += 8; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/x86/macroAssembler_x86.hpp openjdk-17-17.0.4+8/src/hotspot/cpu/x86/macroAssembler_x86.hpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/x86/macroAssembler_x86.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/x86/macroAssembler_x86.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1425,8 +1425,14 @@ void vpxor(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register scratch_reg = rscratch1); // Simple version for AVX2 256bit vectors - void vpxor(XMMRegister dst, XMMRegister src) { Assembler::vpxor(dst, dst, src, true); } - void vpxor(XMMRegister dst, Address src) { Assembler::vpxor(dst, dst, src, true); } + void vpxor(XMMRegister dst, XMMRegister src) { + assert(UseAVX >= 2, "Should be at least AVX2"); + Assembler::vpxor(dst, dst, src, AVX_256bit); + } + void vpxor(XMMRegister dst, Address src) { + assert(UseAVX >= 2, "Should be at least AVX2"); + Assembler::vpxor(dst, dst, src, AVX_256bit); + } void vpermd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { Assembler::vpermd(dst, nds, src, vector_len); } void vpermd(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register scratch_reg); diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/x86/vm_version_x86.hpp openjdk-17-17.0.4+8/src/hotspot/cpu/x86/vm_version_x86.hpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/x86/vm_version_x86.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/x86/vm_version_x86.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,12 +148,11 @@ uint32_t LahfSahf : 1, CmpLegacy : 1, : 3, - lzcnt_intel : 1, lzcnt : 1, sse4a : 1, misalignsse : 1, prefetchw : 1, - : 22; + : 23; } bits; }; @@ -637,10 +636,10 @@ // Intel features. if (is_intel()) { - if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt != 0) { result |= CPU_LZCNT; - // for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw - if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) { + } + if (_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0) { result |= CPU_3DNOW_PREFETCH; } if (_cpuid_info.sef_cpuid7_ebx.bits.clwb != 0) { @@ -650,10 +649,10 @@ // ZX features. if (is_zx()) { - if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt != 0) { result |= CPU_LZCNT; - // for ZX, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw - if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) { + } + if (_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0) { result |= CPU_3DNOW_PREFETCH; } } diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/x86/x86_32.ad openjdk-17-17.0.4+8/src/hotspot/cpu/x86/x86_32.ad --- openjdk-17-17.0.3+7/src/hotspot/cpu/x86/x86_32.ad 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/x86/x86_32.ad 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ // -// Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -7810,9 +7810,9 @@ %} // Divide Register Long -instruct divL_eReg( eADXRegL dst, eRegL src1, eRegL src2, eFlagsReg cr, eCXRegI cx, eBXRegI bx ) %{ +instruct divL_eReg(eADXRegL dst, eRegL src1, eRegL src2) %{ match(Set dst (DivL src1 src2)); - effect( KILL cr, KILL cx, KILL bx ); + effect(CALL); ins_cost(10000); format %{ "PUSH $src1.hi\n\t" "PUSH $src1.lo\n\t" @@ -7858,9 +7858,9 @@ %} // Remainder Register Long -instruct modL_eReg( eADXRegL dst, eRegL src1, eRegL src2, eFlagsReg cr, eCXRegI cx, eBXRegI bx ) %{ +instruct modL_eReg(eADXRegL dst, eRegL src1, eRegL src2) %{ match(Set dst (ModL src1 src2)); - effect( KILL cr, KILL cx, KILL bx ); + effect(CALL); ins_cost(10000); format %{ "PUSH $src1.hi\n\t" "PUSH $src1.lo\n\t" diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/x86/x86.ad openjdk-17-17.0.4+8/src/hotspot/cpu/x86/x86.ad --- openjdk-17-17.0.3+7/src/hotspot/cpu/x86/x86.ad 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/x86/x86.ad 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ // -// Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -1805,17 +1805,9 @@ } break; case Op_VectorCastB2X: - if (size_in_bits == 256 && UseAVX < 2) { - return false; // Implementation limitation - } - break; case Op_VectorCastS2X: - if (is_integral_type(bt) && size_in_bits == 256 && UseAVX < 2) { - return false; - } - break; case Op_VectorCastI2X: - if (is_integral_type(bt) && size_in_bits == 256 && UseAVX < 2) { + if (bt != T_DOUBLE && size_in_bits == 256 && UseAVX < 2) { return false; } break; @@ -4333,7 +4325,8 @@ assert(vector_element_basic_type(this) == T_FLOAT, "sanity"); assert($idx$$constant < (int)vector_length(this), "out of bounds"); - __ insertps($dst$$XMMRegister, $val$$XMMRegister, $idx$$constant); + uint x_idx = $idx$$constant & right_n_bits(2); + __ insertps($dst$$XMMRegister, $val$$XMMRegister, x_idx << 4); %} ins_pipe( pipe_slow ); %} @@ -4353,13 +4346,13 @@ uint y_idx = ($idx$$constant >> 2) & 1; int vlen_enc = Assembler::AVX_256bit; __ vextracti128($vtmp$$XMMRegister, $src$$XMMRegister, y_idx); - __ vinsertps($vtmp$$XMMRegister, $vtmp$$XMMRegister, $val$$XMMRegister, x_idx); + __ vinsertps($vtmp$$XMMRegister, $vtmp$$XMMRegister, $val$$XMMRegister, x_idx << 4); __ vinserti128($dst$$XMMRegister, $src$$XMMRegister, $vtmp$$XMMRegister, y_idx); } else { assert(vlen == 16, "sanity"); uint y_idx = ($idx$$constant >> 2) & 3; __ vextracti32x4($vtmp$$XMMRegister, $src$$XMMRegister, y_idx); - __ vinsertps($vtmp$$XMMRegister, $vtmp$$XMMRegister, $val$$XMMRegister, x_idx); + __ vinsertps($vtmp$$XMMRegister, $vtmp$$XMMRegister, $val$$XMMRegister, x_idx << 4); __ vinserti32x4($dst$$XMMRegister, $src$$XMMRegister, $vtmp$$XMMRegister, y_idx); } %} @@ -6605,11 +6598,12 @@ case T_LONG: __ vpmovsxbq($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); break; - case T_DOUBLE: - __ vpmovsxbd($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + case T_DOUBLE: { + int mid_vlen_enc = (vlen_enc == Assembler::AVX_512bit) ? Assembler::AVX_256bit : Assembler::AVX_128bit; + __ vpmovsxbd($dst$$XMMRegister, $src$$XMMRegister, mid_vlen_enc); __ vcvtdq2pd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); break; - + } default: assert(false, "%s", type2name(to_elem_bt)); } %} @@ -6676,10 +6670,12 @@ case T_LONG: __ vpmovsxwq($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); break; - case T_DOUBLE: - __ vpmovsxwd($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + case T_DOUBLE: { + int mid_vlen_enc = (vlen_enc == Assembler::AVX_512bit) ? Assembler::AVX_256bit : Assembler::AVX_128bit; + __ vpmovsxwd($dst$$XMMRegister, $src$$XMMRegister, mid_vlen_enc); __ vcvtdq2pd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); break; + } default: ShouldNotReachHere(); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp openjdk-17-17.0.4+8/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp --- openjdk-17-17.0.3+7/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -611,6 +611,8 @@ stack->alloc(wordSize); topOfStack = stack->sp(); break; + default: + ; } // Read the field to stack(0) diff -Nru openjdk-17-17.0.3+7/src/hotspot/os/aix/os_aix.cpp openjdk-17-17.0.4+8/src/hotspot/os/aix/os_aix.cpp --- openjdk-17-17.0.3+7/src/hotspot/os/aix/os_aix.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/os/aix/os_aix.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -814,19 +814,24 @@ ret = pthread_attr_setguardsize(&attr, 0); } + ResourceMark rm; pthread_t tid = 0; + if (ret == 0) { - ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); + int limit = 3; + do { + ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); + } while (ret == EAGAIN && limit-- > 0); } if (ret == 0) { char buf[64]; - log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", - (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + log_info(os, thread)("Thread \"%s\" started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + thread->name(), (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } else { char buf[64]; - log_warning(os, thread)("Failed to start thread - pthread_create failed (%d=%s) for attributes: %s.", - ret, os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + log_warning(os, thread)("Failed to start thread \"%s\" - pthread_create failed (%d=%s) for attributes: %s.", + thread->name(), ret, os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); // Log some OS information which might explain why creating the thread failed. log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); LogStream st(Log(os, thread)::info()); diff -Nru openjdk-17-17.0.3+7/src/hotspot/os/bsd/os_bsd.cpp openjdk-17-17.0.4+8/src/hotspot/os/bsd/os_bsd.cpp --- openjdk-17-17.0.3+7/src/hotspot/os/bsd/os_bsd.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/os/bsd/os_bsd.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -633,16 +633,22 @@ ThreadState state; { + + ResourceMark rm; pthread_t tid; - int ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); + int ret = 0; + int limit = 3; + do { + ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); + } while (ret == EAGAIN && limit-- > 0); char buf[64]; if (ret == 0) { - log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", - (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + log_info(os, thread)("Thread \"%s\" started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + thread->name(), (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } else { - log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", - os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + log_warning(os, thread)("Failed to start thread \"%s\" - pthread_create failed (%s) for attributes: %s.", + thread->name(), os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); // Log some OS information which might explain why creating the thread failed. log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); LogStream st(Log(os, thread)::info()); diff -Nru openjdk-17-17.0.3+7/src/hotspot/os/linux/os_linux.cpp openjdk-17-17.0.4+8/src/hotspot/os/linux/os_linux.cpp --- openjdk-17-17.0.3+7/src/hotspot/os/linux/os_linux.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/os/linux/os_linux.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,6 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022 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 @@ -863,16 +864,21 @@ ThreadState state; { + ResourceMark rm; pthread_t tid; - int ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); + int ret = 0; + int limit = 3; + do { + ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); + } while (ret == EAGAIN && limit-- > 0); char buf[64]; if (ret == 0) { - log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", - (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + log_info(os, thread)("Thread \"%s\" started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + thread->name(), (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); } else { - log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", - os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + log_warning(os, thread)("Failed to start thread \"%s\" - pthread_create failed (%s) for attributes: %s.", + thread->name(), os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); // Log some OS information which might explain why creating the thread failed. log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); LogStream st(Log(os, thread)::info()); @@ -2171,6 +2177,34 @@ return false; } +#ifdef __GLIBC__ +// For Glibc, print a one-liner with the malloc tunables. +// Most important and popular is MALLOC_ARENA_MAX, but we are +// thorough and print them all. +static void print_glibc_malloc_tunables(outputStream* st) { + static const char* var[] = { + // the new variant + "GLIBC_TUNABLES", + // legacy variants + "MALLOC_CHECK_", "MALLOC_TOP_PAD_", "MALLOC_PERTURB_", + "MALLOC_MMAP_THRESHOLD_", "MALLOC_TRIM_THRESHOLD_", + "MALLOC_MMAP_MAX_", "MALLOC_ARENA_TEST", "MALLOC_ARENA_MAX", + NULL}; + st->print("glibc malloc tunables: "); + bool printed = false; + for (int i = 0; var[i] != NULL; i ++) { + const char* const val = ::getenv(var[i]); + if (val != NULL) { + st->print("%s%s=%s", (printed ? ", " : ""), var[i], val); + printed = true; + } + } + if (!printed) { + st->print("(default)"); + } +} +#endif // __GLIBC__ + void os::Linux::print_process_memory_info(outputStream* st) { st->print_cr("Process Memory:"); @@ -2193,30 +2227,37 @@ st->print_cr("Could not open /proc/self/status to get process memory related information"); } - // Print glibc outstanding allocations. - // (note: there is no implementation of mallinfo for muslc) + // glibc only: + // - Print outstanding allocations using mallinfo + // - Print glibc tunables #ifdef __GLIBC__ size_t total_allocated = 0; + size_t free_retained = 0; bool might_have_wrapped = false; if (_mallinfo2 != NULL) { struct glibc_mallinfo2 mi = _mallinfo2(); - total_allocated = mi.uordblks; + total_allocated = mi.uordblks + mi.hblkhd; + free_retained = mi.fordblks; } else if (_mallinfo != NULL) { - // mallinfo is an old API. Member names mean next to nothing and, beyond that, are int. - // So values may have wrapped around. Still useful enough to see how much glibc thinks - // we allocated. + // mallinfo is an old API. Member names mean next to nothing and, beyond that, are 32-bit signed. + // So for larger footprints the values may have wrapped around. We try to detect this here: if the + // process whole resident set size is smaller than 4G, malloc footprint has to be less than that + // and the numbers are reliable. struct glibc_mallinfo mi = _mallinfo(); - total_allocated = (size_t)(unsigned)mi.uordblks; + total_allocated = (size_t)(unsigned)mi.uordblks + (size_t)(unsigned)mi.hblkhd; + free_retained = (size_t)(unsigned)mi.fordblks; // Since mallinfo members are int, glibc values may have wrapped. Warn about this. might_have_wrapped = (info.vmrss * K) > UINT_MAX && (info.vmrss * K) > (total_allocated + UINT_MAX); } if (_mallinfo2 != NULL || _mallinfo != NULL) { - st->print_cr("C-Heap outstanding allocations: " SIZE_FORMAT "K%s", - total_allocated / K, + st->print_cr("C-Heap outstanding allocations: " SIZE_FORMAT "K, retained: " SIZE_FORMAT "K%s", + total_allocated / K, free_retained / K, might_have_wrapped ? " (may have wrapped)" : ""); } -#endif // __GLIBC__ - + // Tunables + print_glibc_malloc_tunables(st); + st->cr(); +#endif } bool os::Linux::print_ld_preload_file(outputStream* st) { @@ -2231,6 +2272,19 @@ } } +static void print_container_helper(outputStream* st, jlong j, const char* metrics) { + st->print("%s: ", metrics); + if (j > 0) { + if (j >= 1024) { + st->print_cr(UINT64_FORMAT " k", uint64_t(j) / 1024); + } else { + st->print_cr(UINT64_FORMAT, uint64_t(j)); + } + } else { + st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited"); + } +} + bool os::Linux::print_container_info(outputStream* st) { if (!OSContainer::is_containerized()) { st->print_cr("container information not found."); @@ -2253,7 +2307,11 @@ int i = OSContainer::active_processor_count(); st->print("active_processor_count: "); if (i > 0) { - st->print_cr("%d", i); + if (ActiveProcessorCount > 0) { + st->print_cr("%d, but overridden by -XX:ActiveProcessorCount %d", i, ActiveProcessorCount); + } else { + st->print_cr("%d", i); + } } else { st->print_cr("not supported"); } @@ -2282,47 +2340,13 @@ st->print_cr("%s", i == OSCONTAINER_ERROR ? "not supported" : "no shares"); } - jlong j = OSContainer::memory_limit_in_bytes(); - st->print("memory_limit_in_bytes: "); - if (j > 0) { - st->print_cr(JLONG_FORMAT, j); - } else { - st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited"); - } - - j = OSContainer::memory_and_swap_limit_in_bytes(); - st->print("memory_and_swap_limit_in_bytes: "); - if (j > 0) { - st->print_cr(JLONG_FORMAT, j); - } else { - st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited"); - } - - j = OSContainer::memory_soft_limit_in_bytes(); - st->print("memory_soft_limit_in_bytes: "); - if (j > 0) { - st->print_cr(JLONG_FORMAT, j); - } else { - st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited"); - } - - j = OSContainer::OSContainer::memory_usage_in_bytes(); - st->print("memory_usage_in_bytes: "); - if (j > 0) { - st->print_cr(JLONG_FORMAT, j); - } else { - st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited"); - } - - j = OSContainer::OSContainer::memory_max_usage_in_bytes(); - st->print("memory_max_usage_in_bytes: "); - if (j > 0) { - st->print_cr(JLONG_FORMAT, j); - } else { - st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited"); - } + print_container_helper(st, OSContainer::memory_limit_in_bytes(), "memory_limit_in_bytes"); + print_container_helper(st, OSContainer::memory_and_swap_limit_in_bytes(), "memory_and_swap_limit_in_bytes"); + print_container_helper(st, OSContainer::memory_soft_limit_in_bytes(), "memory_soft_limit_in_bytes"); + print_container_helper(st, OSContainer::memory_usage_in_bytes(), "memory_usage_in_bytes"); + print_container_helper(st, OSContainer::memory_max_usage_in_bytes(), "memory_max_usage_in_bytes"); - j = OSContainer::OSContainer::pids_max(); + jlong j = OSContainer::pids_max(); st->print("maximum number of tasks: "); if (j > 0) { st->print_cr(JLONG_FORMAT, j); @@ -2330,7 +2354,7 @@ st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "unlimited"); } - j = OSContainer::OSContainer::pids_current(); + j = OSContainer::pids_current(); st->print("current number of tasks: "); if (j > 0) { st->print_cr(JLONG_FORMAT, j); @@ -5466,21 +5490,20 @@ } void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) { + // Note: all ranges are "[..)" unsigned long long start = (unsigned long long)addr; unsigned long long end = start + bytes; FILE* f = ::fopen("/proc/self/maps", "r"); int num_found = 0; if (f != NULL) { - st->print("Range [%llx-%llx) contains: ", start, end); + st->print_cr("Range [%llx-%llx) contains: ", start, end); char line[512]; while(fgets(line, sizeof(line), f) == line) { - unsigned long long a1 = 0; - unsigned long long a2 = 0; - if (::sscanf(line, "%llx-%llx", &a1, &a2) == 2) { + unsigned long long segment_start = 0; + unsigned long long segment_end = 0; + if (::sscanf(line, "%llx-%llx", &segment_start, &segment_end) == 2) { // Lets print out every range which touches ours. - if ((a1 >= start && a1 < end) || // left leg in - (a2 >= start && a2 < end) || // right leg in - (a1 < start && a2 >= end)) { // superimposition + if (segment_start < end && segment_end > start) { num_found ++; st->print("%s", line); // line includes \n } @@ -5488,7 +5511,7 @@ } ::fclose(f); if (num_found == 0) { - st->print("nothing."); + st->print_cr("nothing."); } st->cr(); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/os/windows/os_windows.cpp openjdk-17-17.0.4+8/src/hotspot/os/windows/os_windows.cpp --- openjdk-17-17.0.3+7/src/hotspot/os/windows/os_windows.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/os/windows/os_windows.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -746,21 +746,27 @@ // flag appears to work with _beginthredex() as well. const unsigned initflag = CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION; - HANDLE thread_handle = - (HANDLE)_beginthreadex(NULL, - (unsigned)stack_size, - (unsigned (__stdcall *)(void*)) thread_native_entry, - thread, - initflag, - &thread_id); + HANDLE thread_handle; + int limit = 3; + do { + thread_handle = + (HANDLE)_beginthreadex(NULL, + (unsigned)stack_size, + (unsigned (__stdcall *)(void*)) thread_native_entry, + thread, + initflag, + &thread_id); + } while (thread_handle == NULL && errno == EAGAIN && limit-- > 0); + ResourceMark rm; char buf[64]; if (thread_handle != NULL) { - log_info(os, thread)("Thread started (tid: %u, attributes: %s)", - thread_id, describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + log_info(os, thread)("Thread \"%s\" started (tid: %u, attributes: %s)", + thread->name(), thread_id, + describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); } else { - log_warning(os, thread)("Failed to start thread - _beginthreadex failed (%s) for attributes: %s.", - os::errno_name(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + log_warning(os, thread)("Failed to start thread \"%s\" - _beginthreadex failed (%s) for attributes: %s.", + thread->name(), os::errno_name(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); // Log some OS information which might explain why creating the thread failed. log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); LogStream st(Log(os, thread)::info()); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/adlArena.cpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/adlArena.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/adlArena.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/adlArena.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 "adlc.hpp" + +void* AdlAllocateHeap(size_t size) { + unsigned char* ptr = (unsigned char*) malloc(size); + if (ptr == NULL && size != 0) { + fprintf(stderr, "Error: Out of memory in ADLC\n"); // logging can cause crash! + fflush(stderr); + exit(1); + } + return ptr; +} + +void* AdlReAllocateHeap(void* old_ptr, size_t size) { + unsigned char* ptr = (unsigned char*) realloc(old_ptr, size); + if (ptr == NULL && size != 0) { + fprintf(stderr, "Error: Out of memory in ADLC\n"); // logging can cause crash! + fflush(stderr); + exit(1); + } + return ptr; +} + +void* AdlChunk::operator new(size_t requested_size, size_t length) throw() { + return AdlCHeapObj::operator new(requested_size + length); +} + +void AdlChunk::operator delete(void* p, size_t length) { + AdlCHeapObj::operator delete(p); +} + +AdlChunk::AdlChunk(size_t length) { + _next = NULL; // Chain on the linked list + _len = length; // Save actual size +} + +//------------------------------chop------------------------------------------- +void AdlChunk::chop() { + AdlChunk *k = this; + while( k ) { + AdlChunk *tmp = k->_next; + // clear out this chunk (to detect allocation bugs) + memset(k, 0xBE, k->_len); + free(k); // Free chunk (was malloc'd) + k = tmp; + } +} + +void AdlChunk::next_chop() { + _next->chop(); + _next = NULL; +} + +//------------------------------AdlArena------------------------------------------ +AdlArena::AdlArena( size_t init_size ) { + init_size = (init_size+3) & ~3; + _first = _chunk = new (init_size) AdlChunk(init_size); + _hwm = _chunk->bottom(); // Save the cached hwm, max + _max = _chunk->top(); + set_size_in_bytes(init_size); +} + +AdlArena::AdlArena() { + _first = _chunk = new (AdlChunk::init_size) AdlChunk(AdlChunk::init_size); + _hwm = _chunk->bottom(); // Save the cached hwm, max + _max = _chunk->top(); + set_size_in_bytes(AdlChunk::init_size); +} + +AdlArena::AdlArena( AdlArena *a ) +: _chunk(a->_chunk), _hwm(a->_hwm), _max(a->_max), _first(a->_first) { + set_size_in_bytes(a->size_in_bytes()); +} + +//------------------------------used------------------------------------------- +// Total of all AdlChunks in arena +size_t AdlArena::used() const { + size_t sum = _chunk->_len - (_max-_hwm); // Size leftover in this AdlChunk + AdlChunk *k = _first; + while( k != _chunk) { // Whilst have AdlChunks in a row + sum += k->_len; // Total size of this AdlChunk + k = k->_next; // Bump along to next AdlChunk + } + return sum; // Return total consumed space. +} + +//------------------------------grow------------------------------------------- +// Grow a new AdlChunk +void* AdlArena::grow( size_t x ) { + // Get minimal required size. Either real big, or even bigger for giant objs + size_t len = max(x, AdlChunk::size); + + AdlChunk *k = _chunk; // Get filled-up chunk address + _chunk = new (len) AdlChunk(len); + + if( k ) k->_next = _chunk; // Append new chunk to end of linked list + else _first = _chunk; + _hwm = _chunk->bottom(); // Save the cached hwm, max + _max = _chunk->top(); + set_size_in_bytes(size_in_bytes() + len); + void* result = _hwm; + _hwm += x; + return result; +} + +//------------------------------calloc----------------------------------------- +// Allocate zeroed storage in AdlArena +void *AdlArena::Acalloc( size_t items, size_t x ) { + size_t z = items*x; // Total size needed + void *ptr = Amalloc(z); // Get space + memset( ptr, 0, z ); // Zap space + return ptr; // Return space +} + +//------------------------------realloc---------------------------------------- +// Reallocate storage in AdlArena. +void *AdlArena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { + char *c_old = (char*)old_ptr; // Handy name + // Stupid fast special case + if( new_size <= old_size ) { // Shrink in-place + if( c_old+old_size == _hwm) // Attempt to free the excess bytes + _hwm = c_old+new_size; // Adjust hwm + return c_old; + } + + // See if we can resize in-place + if( (c_old+old_size == _hwm) && // Adjusting recent thing + (c_old+new_size <= _max) ) { // Still fits where it sits + _hwm = c_old+new_size; // Adjust hwm + return c_old; // Return old pointer + } + + // Oops, got to relocate guts + void *new_ptr = Amalloc(new_size); + memcpy( new_ptr, c_old, old_size ); + Afree(c_old,old_size); // Mostly done to keep stats accurate + return new_ptr; +} + +//------------------------------reset------------------------------------------ +// Reset this AdlArena to empty, and return this AdlArenas guts in a new AdlArena. +AdlArena *AdlArena::reset(void) { + AdlArena *a = new AdlArena(this); // New empty arena + _first = _chunk = NULL; // Normal, new-arena initialization + _hwm = _max = NULL; + return a; // Return AdlArena with guts +} + +//------------------------------contains--------------------------------------- +// Determine if pointer belongs to this AdlArena or not. +bool AdlArena::contains( const void *ptr ) const { + if( (void*)_chunk->bottom() <= ptr && ptr < (void*)_hwm ) + return true; // Check for in this chunk + for( AdlChunk *c = _first; c; c = c->_next ) + if( (void*)c->bottom() <= ptr && ptr < (void*)c->top()) + return true; // Check for every chunk in AdlArena + return false; // Not in any AdlChunk, so not in AdlArena +} + +//----------------------------------------------------------------------------- +// CHeapObj + +void* AdlCHeapObj::operator new(size_t size) throw() { + return (void *) AdlAllocateHeap(size); +} + +void AdlCHeapObj::operator delete(void* p){ + free(p); +} diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/adlArena.hpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/adlArena.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/adlArena.hpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/adlArena.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 SHARE_ADLC_ADLARENA_HPP +#define SHARE_ADLC_ADLARENA_HPP + +void* AdlAllocateHeap(size_t size); +void* AdlReAllocateHeap(void* old_ptr, size_t size); + +// All classes in adlc may be derived +// from one of the following allocation classes: +// +// For objects allocated in the C-heap (managed by: malloc & free). +// - CHeapObj +// +// For classes used as name spaces. +// - AdlAllStatic +// + +class AdlCHeapObj { + public: + void* operator new(size_t size) throw(); + void operator delete(void* p); + void* new_array(size_t size); +}; + +// Base class for classes that constitute name spaces. + +class AdlAllStatic { + public: + void* operator new(size_t size) throw(); + void operator delete(void* p); +}; + + +//------------------------------AdlChunk------------------------------------------ +// Linked list of raw memory chunks +class AdlChunk: public AdlCHeapObj { + private: + // This ordinary operator delete is needed even though not used, so the + // below two-argument operator delete will be treated as a placement + // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2. + void operator delete(void* p); + public: + void* operator new(size_t size, size_t length) throw(); + void operator delete(void* p, size_t length); + AdlChunk(size_t length); + + enum { + init_size = 1*1024, // Size of first chunk + size = 32*1024 // Default size of an AdlArena chunk (following the first) + }; + AdlChunk* _next; // Next AdlChunk in list + size_t _len; // Size of this AdlChunk + + void chop(); // Chop this chunk + void next_chop(); // Chop next chunk + + // Boundaries of data area (possibly unused) + char* bottom() const { return ((char*) this) + sizeof(AdlChunk); } + char* top() const { return bottom() + _len; } +}; + + +//------------------------------AdlArena------------------------------------------ +// Fast allocation of memory +class AdlArena: public AdlCHeapObj { +protected: + friend class ResourceMark; + friend class HandleMark; + friend class NoHandleMark; + AdlChunk *_first; // First chunk + AdlChunk *_chunk; // current chunk + char *_hwm, *_max; // High water mark and max in current chunk + void* grow(size_t x); // Get a new AdlChunk of at least size x + size_t _size_in_bytes; // Size of arena (used for memory usage tracing) +public: + AdlArena(); + AdlArena(size_t init_size); + AdlArena(AdlArena *old); + ~AdlArena() { _first->chop(); } + char* hwm() const { return _hwm; } + + // Fast allocate in the arena. Common case is: pointer test + increment. + void* Amalloc(size_t x) { +#ifdef _LP64 + x = (x + (8-1)) & ((unsigned)(-8)); +#else + x = (x + (4-1)) & ((unsigned)(-4)); +#endif + if (_hwm + x > _max) { + return grow(x); + } else { + char *old = _hwm; + _hwm += x; + return old; + } + } + // Further assume size is padded out to words + // Warning: in LP64, Amalloc_4 is really Amalloc_8 + void *Amalloc_4(size_t x) { + assert( (x&(sizeof(char*)-1)) == 0, "misaligned size" ); + if (_hwm + x > _max) { + return grow(x); + } else { + char *old = _hwm; + _hwm += x; + return old; + } + } + + // Fast delete in area. Common case is: NOP (except for storage reclaimed) + void Afree(void *ptr, size_t size) { + if (((char*)ptr) + size == _hwm) _hwm = (char*)ptr; + } + + void *Acalloc( size_t items, size_t x ); + void *Arealloc( void *old_ptr, size_t old_size, size_t new_size ); + + // Reset this AdlArena to empty, and return this AdlArenas guts in a new AdlArena. + AdlArena *reset(void); + + // Determine if pointer belongs to this AdlArena or not. + bool contains( const void *ptr ) const; + + // Total of all chunks in use (not thread-safe) + size_t used() const; + + // Total # of bytes used + size_t size_in_bytes() const { return _size_in_bytes; } + void set_size_in_bytes(size_t size) { _size_in_bytes = size; } +}; + +#endif // SHARE_ADLC_ADLARENA_HPP diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/adlc.hpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/adlc.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/adlc.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/adlc.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -93,7 +93,7 @@ #define max(a, b) (((a)>(b)) ? (a) : (b)) // ADLC components -#include "arena.hpp" +#include "adlArena.hpp" #include "opto/adlcVMDeps.hpp" #include "filebuff.hpp" #include "dict2.hpp" diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/adlparse.cpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/adlparse.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/adlparse.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/adlparse.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,7 +211,7 @@ return; } assert(match_rules_cnt < 100," too many match rule clones"); - char* buf = (char*) AllocateHeap(strlen(instr->_ident) + 4); + char* buf = (char*) AdlAllocateHeap(strlen(instr->_ident) + 4); sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++); rule->_result = buf; // Check for commutative operations with tree operands. @@ -2805,7 +2805,7 @@ // Create a new encoding name based on the name of the instruction // definition, which should be unique. const char* prefix = "__ins_encode_"; - char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); + char* ec_name = (char*) AdlAllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); sprintf(ec_name, "%s%s", prefix, inst._ident); assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); @@ -3276,7 +3276,7 @@ // Create a new encoding name based on the name of the instruction // definition, which should be unique. const char* prefix = "__constant_"; - char* ec_name = (char*) AllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); + char* ec_name = (char*) AdlAllocateHeap(strlen(inst._ident) + strlen(prefix) + 1); sprintf(ec_name, "%s%s", prefix, inst._ident); assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); @@ -4409,7 +4409,7 @@ if (_AD._adlocation_debug) { char* location = get_line_string(line); char* end_loc = end_line_marker(); - char* result = (char *)AllocateHeap(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); + char* result = (char *)AdlAllocateHeap(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1); strcpy(result, location); strcat(result, cppBlock); strcat(result, end_loc); @@ -4498,7 +4498,7 @@ // Prepend location descriptor, for debugging. char* location = get_line_string(line); char* end_loc = end_line_marker(); - char* result = (char *)AllocateHeap(strlen(location) + strlen(token2) + strlen(end_loc) + 1); + char* result = (char *)AdlAllocateHeap(strlen(location) + strlen(token2) + strlen(end_loc) + 1); strcpy(result, location); strcat(result, token2); strcat(result, end_loc); @@ -4596,7 +4596,7 @@ // Grab a constant expression. param = get_paren_expr(description); if (param[0] != '(') { - char* buf = (char*) AllocateHeap(strlen(param) + 3); + char* buf = (char*) AdlAllocateHeap(strlen(param) + 3); sprintf(buf, "(%s)", param); param = buf; } @@ -5204,7 +5204,7 @@ char* ADLParser::get_line_string(int linenum) { const char* file = _AD._ADL_file._name; int line = linenum ? linenum : this->linenum(); - char* location = (char *)AllocateHeap(strlen(file) + 100); + char* location = (char *)AdlAllocateHeap(strlen(file) + 100); sprintf(location, "\n#line %d \"%s\"\n", line, file); return location; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/arena.cpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/arena.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/arena.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/arena.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,192 +0,0 @@ -/* - * Copyright (c) 1998, 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. - * - */ - -#include "adlc.hpp" - -void* AllocateHeap(size_t size) { - unsigned char* ptr = (unsigned char*) malloc(size); - if (ptr == NULL && size != 0) { - fprintf(stderr, "Error: Out of memory in ADLC\n"); // logging can cause crash! - fflush(stderr); - exit(1); - } - return ptr; -} - -void* ReAllocateHeap(void* old_ptr, size_t size) { - unsigned char* ptr = (unsigned char*) realloc(old_ptr, size); - if (ptr == NULL && size != 0) { - fprintf(stderr, "Error: Out of memory in ADLC\n"); // logging can cause crash! - fflush(stderr); - exit(1); - } - return ptr; -} - -void* Chunk::operator new(size_t requested_size, size_t length) throw() { - return CHeapObj::operator new(requested_size + length); -} - -void Chunk::operator delete(void* p, size_t length) { - CHeapObj::operator delete(p); -} - -Chunk::Chunk(size_t length) { - _next = NULL; // Chain on the linked list - _len = length; // Save actual size -} - -//------------------------------chop------------------------------------------- -void Chunk::chop() { - Chunk *k = this; - while( k ) { - Chunk *tmp = k->_next; - // clear out this chunk (to detect allocation bugs) - memset(k, 0xBE, k->_len); - free(k); // Free chunk (was malloc'd) - k = tmp; - } -} - -void Chunk::next_chop() { - _next->chop(); - _next = NULL; -} - -//------------------------------Arena------------------------------------------ -Arena::Arena( size_t init_size ) { - init_size = (init_size+3) & ~3; - _first = _chunk = new (init_size) Chunk(init_size); - _hwm = _chunk->bottom(); // Save the cached hwm, max - _max = _chunk->top(); - set_size_in_bytes(init_size); -} - -Arena::Arena() { - _first = _chunk = new (Chunk::init_size) Chunk(Chunk::init_size); - _hwm = _chunk->bottom(); // Save the cached hwm, max - _max = _chunk->top(); - set_size_in_bytes(Chunk::init_size); -} - -Arena::Arena( Arena *a ) -: _chunk(a->_chunk), _hwm(a->_hwm), _max(a->_max), _first(a->_first) { - set_size_in_bytes(a->size_in_bytes()); -} - -//------------------------------used------------------------------------------- -// Total of all Chunks in arena -size_t Arena::used() const { - size_t sum = _chunk->_len - (_max-_hwm); // Size leftover in this Chunk - Chunk *k = _first; - while( k != _chunk) { // Whilst have Chunks in a row - sum += k->_len; // Total size of this Chunk - k = k->_next; // Bump along to next Chunk - } - return sum; // Return total consumed space. -} - -//------------------------------grow------------------------------------------- -// Grow a new Chunk -void* Arena::grow( size_t x ) { - // Get minimal required size. Either real big, or even bigger for giant objs - size_t len = max(x, Chunk::size); - - Chunk *k = _chunk; // Get filled-up chunk address - _chunk = new (len) Chunk(len); - - if( k ) k->_next = _chunk; // Append new chunk to end of linked list - else _first = _chunk; - _hwm = _chunk->bottom(); // Save the cached hwm, max - _max = _chunk->top(); - set_size_in_bytes(size_in_bytes() + len); - void* result = _hwm; - _hwm += x; - return result; -} - -//------------------------------calloc----------------------------------------- -// Allocate zeroed storage in Arena -void *Arena::Acalloc( size_t items, size_t x ) { - size_t z = items*x; // Total size needed - void *ptr = Amalloc(z); // Get space - memset( ptr, 0, z ); // Zap space - return ptr; // Return space -} - -//------------------------------realloc---------------------------------------- -// Reallocate storage in Arena. -void *Arena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { - char *c_old = (char*)old_ptr; // Handy name - // Stupid fast special case - if( new_size <= old_size ) { // Shrink in-place - if( c_old+old_size == _hwm) // Attempt to free the excess bytes - _hwm = c_old+new_size; // Adjust hwm - return c_old; - } - - // See if we can resize in-place - if( (c_old+old_size == _hwm) && // Adjusting recent thing - (c_old+new_size <= _max) ) { // Still fits where it sits - _hwm = c_old+new_size; // Adjust hwm - return c_old; // Return old pointer - } - - // Oops, got to relocate guts - void *new_ptr = Amalloc(new_size); - memcpy( new_ptr, c_old, old_size ); - Afree(c_old,old_size); // Mostly done to keep stats accurate - return new_ptr; -} - -//------------------------------reset------------------------------------------ -// Reset this Arena to empty, and return this Arenas guts in a new Arena. -Arena *Arena::reset(void) { - Arena *a = new Arena(this); // New empty arena - _first = _chunk = NULL; // Normal, new-arena initialization - _hwm = _max = NULL; - return a; // Return Arena with guts -} - -//------------------------------contains--------------------------------------- -// Determine if pointer belongs to this Arena or not. -bool Arena::contains( const void *ptr ) const { - if( (void*)_chunk->bottom() <= ptr && ptr < (void*)_hwm ) - return true; // Check for in this chunk - for( Chunk *c = _first; c; c = c->_next ) - if( (void*)c->bottom() <= ptr && ptr < (void*)c->top()) - return true; // Check for every chunk in Arena - return false; // Not in any Chunk, so not in Arena -} - -//----------------------------------------------------------------------------- -// CHeapObj - -void* CHeapObj::operator new(size_t size) throw() { - return (void *) AllocateHeap(size); -} - -void CHeapObj::operator delete(void* p){ - free(p); -} diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/arena.hpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/arena.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/arena.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/arena.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. - * 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 SHARE_ADLC_ARENA_HPP -#define SHARE_ADLC_ARENA_HPP - -void* AllocateHeap(size_t size); -void* ReAllocateHeap(void* old_ptr, size_t size); - -// All classes in adlc may be derived -// from one of the following allocation classes: -// -// For objects allocated in the C-heap (managed by: malloc & free). -// - CHeapObj -// -// For classes used as name spaces. -// - AllStatic -// - -class CHeapObj { - public: - void* operator new(size_t size) throw(); - void operator delete(void* p); - void* new_array(size_t size); -}; - -// Base class for classes that constitute name spaces. - -class AllStatic { - public: - void* operator new(size_t size) throw(); - void operator delete(void* p); -}; - - -//------------------------------Chunk------------------------------------------ -// Linked list of raw memory chunks -class Chunk: public CHeapObj { - private: - // This ordinary operator delete is needed even though not used, so the - // below two-argument operator delete will be treated as a placement - // delete rather than an ordinary sized delete; see C++14 3.7.4.2/p2. - void operator delete(void* p); - public: - void* operator new(size_t size, size_t length) throw(); - void operator delete(void* p, size_t length); - Chunk(size_t length); - - enum { - init_size = 1*1024, // Size of first chunk - size = 32*1024 // Default size of an Arena chunk (following the first) - }; - Chunk* _next; // Next Chunk in list - size_t _len; // Size of this Chunk - - void chop(); // Chop this chunk - void next_chop(); // Chop next chunk - - // Boundaries of data area (possibly unused) - char* bottom() const { return ((char*) this) + sizeof(Chunk); } - char* top() const { return bottom() + _len; } -}; - - -//------------------------------Arena------------------------------------------ -// Fast allocation of memory -class Arena: public CHeapObj { -protected: - friend class ResourceMark; - friend class HandleMark; - friend class NoHandleMark; - Chunk *_first; // First chunk - Chunk *_chunk; // current chunk - char *_hwm, *_max; // High water mark and max in current chunk - void* grow(size_t x); // Get a new Chunk of at least size x - size_t _size_in_bytes; // Size of arena (used for memory usage tracing) -public: - Arena(); - Arena(size_t init_size); - Arena(Arena *old); - ~Arena() { _first->chop(); } - char* hwm() const { return _hwm; } - - // Fast allocate in the arena. Common case is: pointer test + increment. - void* Amalloc(size_t x) { -#ifdef _LP64 - x = (x + (8-1)) & ((unsigned)(-8)); -#else - x = (x + (4-1)) & ((unsigned)(-4)); -#endif - if (_hwm + x > _max) { - return grow(x); - } else { - char *old = _hwm; - _hwm += x; - return old; - } - } - // Further assume size is padded out to words - // Warning: in LP64, Amalloc_4 is really Amalloc_8 - void *Amalloc_4(size_t x) { - assert( (x&(sizeof(char*)-1)) == 0, "misaligned size" ); - if (_hwm + x > _max) { - return grow(x); - } else { - char *old = _hwm; - _hwm += x; - return old; - } - } - - // Fast delete in area. Common case is: NOP (except for storage reclaimed) - void Afree(void *ptr, size_t size) { - if (((char*)ptr) + size == _hwm) _hwm = (char*)ptr; - } - - void *Acalloc( size_t items, size_t x ); - void *Arealloc( void *old_ptr, size_t old_size, size_t new_size ); - - // Reset this Arena to empty, and return this Arenas guts in a new Arena. - Arena *reset(void); - - // Determine if pointer belongs to this Arena or not. - bool contains( const void *ptr ) const; - - // Total of all chunks in use (not thread-safe) - size_t used() const; - - // Total # of bytes used - size_t size_in_bytes() const { return _size_in_bytes; } - void set_size_in_bytes(size_t size) { _size_in_bytes = size; } -}; - -#endif // SHARE_ADLC_ARENA_HPP diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/dfa.cpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/dfa.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/dfa.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/dfa.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * 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 @@ public: // cmpstr does string comparisions. hashstr computes a key. - ProductionState(Arena *arena) : _production(cmpstr, hashstr, arena) { initialize(); }; + ProductionState(AdlArena *arena) : _production(cmpstr, hashstr, arena) { initialize(); }; ~ProductionState() { }; void initialize(); // reset local and dictionary state @@ -817,7 +817,7 @@ //------------------------------ExprDict--------------------------------------- // Constructor -ExprDict::ExprDict( CmpKey cmp, Hash hash, Arena *arena ) +ExprDict::ExprDict( CmpKey cmp, Hash hash, AdlArena *arena ) : _expr(cmp, hash, arena), _defines() { } ExprDict::~ExprDict() { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/dict2.cpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/dict2.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/dict2.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/dict2.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ init(); } -Dict::Dict(CmpKey initcmp, Hash inithash, Arena *arena) : _hash(inithash), _cmp(initcmp), _arena(arena) { +Dict::Dict(CmpKey initcmp, Hash inithash, AdlArena *arena) : _hash(inithash), _cmp(initcmp), _arena(arena) { init(); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/dict2.hpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/dict2.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/dict2.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/dict2.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * 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 @@ class Dict { // Dictionary structure private: - class Arena *_arena; // Where to draw storage from + class AdlArena *_arena; // Where to draw storage from class bucket *_bin; // Hash table is array of buckets int _size; // Size (# of slots) in hash table int _cnt; // Number of key-value pairs in hash table @@ -56,7 +56,7 @@ // cmp is a key comparision routine. hash is a routine to hash a key. Dict( CmpKey cmp, Hash hash ); - Dict( CmpKey cmp, Hash hash, Arena *arena ); + Dict( CmpKey cmp, Hash hash, AdlArena *arena ); void init(); ~Dict(); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/forms.cpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/forms.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/forms.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/forms.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * 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,9 +27,9 @@ //------------------------------Static Initializers---------------------------- // allocate arena used by forms -Arena *Form::arena = Form::generate_arena(); // = Form::generate_arena(); -Arena *Form::generate_arena() { - return (new Arena); +AdlArena *Form::arena = Form::generate_arena(); // = Form::generate_arena(); +AdlArena *Form::generate_arena() { + return (new AdlArena); } //------------------------------NameList--------------------------------------- @@ -40,7 +40,7 @@ // Constructor and Destructor NameList::NameList() : _cur(0), _max(4), _iter(0), _justReset(true) { - _names = (const char**) AllocateHeap(_max*sizeof(char*)); + _names = (const char**) AdlAllocateHeap(_max*sizeof(char*)); } NameList::~NameList() { // The following free is a double-free, and crashes the program: @@ -49,7 +49,7 @@ void NameList::addName(const char *name) { if (_cur == _max) { - _names = (const char**) ReAllocateHeap(_names, (_max *=2)*sizeof(char*)); + _names = (const char**) AdlReAllocateHeap(_names, (_max *=2)*sizeof(char*)); } _names[_cur++] = name; } @@ -310,7 +310,7 @@ //------------------------------FormDict--------------------------------------- // Constructor -FormDict::FormDict( CmpKey cmp, Hash hash, Arena *arena ) +FormDict::FormDict( CmpKey cmp, Hash hash, AdlArena *arena ) : _form(cmp, hash, arena) { } FormDict::~FormDict() { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/forms.hpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/forms.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/forms.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/forms.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ public: // cmp is a key comparision routine. hash is a routine to hash a key. // FormDict( CmpKey cmp, Hash hash ); - FormDict( CmpKey cmp, Hash hash, Arena *arena ); + FormDict( CmpKey cmp, Hash hash, AdlArena *arena ); FormDict( const FormDict & fd ); // Deep-copy guts ~FormDict(); @@ -119,9 +119,9 @@ //------------------------------Form------------------------------------------- class Form { public: - static Arena *arena; // arena used by forms + static AdlArena *arena; // arena used by forms private: - static Arena *generate_arena(); // allocate arena used by forms + static AdlArena *generate_arena(); // allocate arena used by forms protected: int _ftype; // Indicator for derived class type @@ -573,7 +573,7 @@ public: // cmp is a key comparision routine. hash is a routine to hash a key. - ExprDict( CmpKey cmp, Hash hash, Arena *arena ); + ExprDict( CmpKey cmp, Hash hash, AdlArena *arena ); ~ExprDict(); // Return # of key-value pairs in dict diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/formsopt.cpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/formsopt.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/formsopt.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/formsopt.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,7 +206,7 @@ _concrete(concrete), _register_num(0) { - // Chunk and register mask are determined by the register number + // AdlChunk and register mask are determined by the register number // _register_num is set when registers are added to an allocation class } RegDef::~RegDef() { // Destructor diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/adlc/formssel.cpp openjdk-17-17.0.4+8/src/hotspot/share/adlc/formssel.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/adlc/formssel.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/adlc/formssel.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1366,7 +1366,7 @@ // component back to an index and any DEF always goes at 0 so the // length of the array has to be the number of components + 1. _uniq_idx_length = _components.count() + 1; - uniq_idx = (uint*) AllocateHeap(sizeof(uint) * _uniq_idx_length); + uniq_idx = (uint*) AdlAllocateHeap(sizeof(uint) * _uniq_idx_length); for (i = 0; i < _uniq_idx_length; i++) { uniq_idx[i] = i; } @@ -3475,7 +3475,7 @@ rstr = (_rChild) ? ((_rChild->_internalop) ? _rChild->_internalop : _rChild->_opType) : ""; len += (int)strlen(lstr) + (int)strlen(rstr); - subtree = (char *)AllocateHeap(len); + subtree = (char *)AdlAllocateHeap(len); sprintf(subtree,"_%s_%s_%s", _opType, lstr, rstr); // Hash the subtree string in _internalOps; if a name exists, use it iop = (char *)_AD._internalOps[subtree]; @@ -3898,7 +3898,7 @@ MatchRule* clone = new MatchRule(_AD, this); // Swap operands of commutative operation ((MatchNode*)clone)->swap_commutative_op(true, count); - char* buf = (char*) AllocateHeap(strlen(instr_ident) + 4); + char* buf = (char*) AdlAllocateHeap(strlen(instr_ident) + 4); sprintf(buf, "%s_%d", instr_ident, match_rules_cnt++); clone->_result = buf; diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/asm/codeBuffer.cpp openjdk-17-17.0.4+8/src/hotspot/share/asm/codeBuffer.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/asm/codeBuffer.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/asm/codeBuffer.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -135,11 +135,10 @@ // Previous incarnations of this buffer are held live, so that internal // addresses constructed before expansions will not be confused. cb->free_blob(); + // free any overflow storage + delete cb->_overflow_arena; } - // free any overflow storage - delete _overflow_arena; - // Claim is that stack allocation ensures resources are cleaned up. // This is resource clean up, let's hope that all were properly copied out. NOT_PRODUCT(free_strings();) @@ -942,6 +941,7 @@ this_sect->take_over_code_from(cb_sect); } _overflow_arena = cb->_overflow_arena; + cb->_overflow_arena = NULL; // Make sure the old cb won't try to use it or free it. DEBUG_ONLY(cb->_blob = (BufferBlob*)badAddress); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/c1/c1_GraphBuilder.cpp openjdk-17-17.0.4+8/src/hotspot/share/c1/c1_GraphBuilder.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/c1/c1_GraphBuilder.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/c1/c1_GraphBuilder.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1865,22 +1865,17 @@ log->identify(target), Bytecodes::name(code)); - // invoke-special-super - if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer()) { - ciInstanceKlass* sender_klass = calling_klass; - if (sender_klass->is_interface()) { - int index = state()->stack_size() - (target->arg_size_no_receiver() + 1); - Value receiver = state()->stack_at(index); - CheckCast* c = new CheckCast(sender_klass, receiver, copy_state_before()); - c->set_invokespecial_receiver_check(); - state()->stack_at_put(index, append_split(c)); - } - } - // Some methods are obviously bindable without any type checks so // convert them directly to an invokespecial or invokestatic. if (target->is_loaded() && !target->is_abstract() && target->can_be_statically_bound()) { switch (bc_raw) { + case Bytecodes::_invokeinterface: + // convert to invokespecial if the target is the private interface method. + if (target->is_private()) { + assert(holder->is_interface(), "How did we get a non-interface method here!"); + code = Bytecodes::_invokespecial; + } + break; case Bytecodes::_invokevirtual: code = Bytecodes::_invokespecial; break; @@ -1897,6 +1892,26 @@ } } + if (code == Bytecodes::_invokespecial) { + // Additional receiver subtype checks for interface calls via invokespecial or invokeinterface. + ciKlass* receiver_constraint = nullptr; + + if (bc_raw == Bytecodes::_invokeinterface) { + receiver_constraint = holder; + } else if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer() && calling_klass->is_interface()) { + receiver_constraint = calling_klass; + } + + if (receiver_constraint != nullptr) { + int index = state()->stack_size() - (target->arg_size_no_receiver() + 1); + Value receiver = state()->stack_at(index); + CheckCast* c = new CheckCast(receiver_constraint, receiver, copy_state_before()); + // go to uncommon_trap when checkcast fails + c->set_invokespecial_receiver_check(); + state()->stack_at_put(index, append_split(c)); + } + } + // Push appendix argument (MethodType, CallSite, etc.), if one. bool patch_for_appendix = false; int patching_appendix_arg = 0; @@ -2025,9 +2040,11 @@ } // check if we could do inlining - if (!PatchALot && Inline && target->is_loaded() && callee_holder->is_linked() && !patch_for_appendix) { + if (!PatchALot && Inline && target->is_loaded() && !patch_for_appendix && + callee_holder->is_loaded()) { // the effect of symbolic reference resolution + // callee is known => check if we have static binding - if ((code == Bytecodes::_invokestatic && callee_holder->is_initialized()) || // invokestatic involves an initialization barrier on resolved klass + if ((code == Bytecodes::_invokestatic && klass->is_initialized()) || // invokestatic involves an initialization barrier on declaring class code == Bytecodes::_invokespecial || (code == Bytecodes::_invokevirtual && target->is_final_method()) || code == Bytecodes::_invokedynamic) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/c1/c1_RangeCheckElimination.cpp openjdk-17-17.0.4+8/src/hotspot/share/c1/c1_RangeCheckElimination.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/c1/c1_RangeCheckElimination.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/c1/c1_RangeCheckElimination.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -365,7 +365,12 @@ bool RangeCheckEliminator::loop_invariant(BlockBegin *loop_header, Instruction *instruction) { assert(loop_header, "Loop header must not be null!"); if (!instruction) return true; - return instruction->dominator_depth() < loop_header->dominator_depth(); + for (BlockBegin *d = loop_header->dominator(); d != NULL; d = d->dominator()) { + if (d == instruction->block()) { + return true; + } + } + return false; } // Update bound. Pushes a new bound onto the stack. Tries to do a conjunction with the current bound. diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/cds/filemap.cpp openjdk-17-17.0.4+8/src/hotspot/share/cds/filemap.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/cds/filemap.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/cds/filemap.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -165,9 +165,9 @@ assert(header_version[JVM_IDENT_MAX-1] == 0, "must be"); } -FileMapInfo::FileMapInfo(bool is_static) { - memset((void*)this, 0, sizeof(FileMapInfo)); - _is_static = is_static; +FileMapInfo::FileMapInfo(bool is_static) : + _is_static(is_static), _file_open(false), _is_mapped(false), _fd(-1), _file_offset(0), + _full_path(nullptr), _base_archive_name(nullptr), _header(nullptr) { size_t header_size; if (is_static) { assert(_current_info == NULL, "must be singleton"); // not thread safe @@ -183,8 +183,6 @@ _header->set_header_size(header_size); _header->set_version(INVALID_CDS_ARCHIVE_VERSION); _header->set_has_platform_or_app_classes(true); - _file_offset = 0; - _file_open = false; } FileMapInfo::~FileMapInfo() { @@ -195,6 +193,14 @@ assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe _dynamic_archive_info = NULL; } + + if (_header != nullptr) { + os::free(_header); + } + + if (_file_open) { + ::close(_fd); + } } void FileMapInfo::populate_header(size_t core_region_alignment) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/ci/bcEscapeAnalyzer.cpp openjdk-17-17.0.4+8/src/hotspot/share/ci/bcEscapeAnalyzer.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/ci/bcEscapeAnalyzer.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/ci/bcEscapeAnalyzer.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -416,11 +416,11 @@ // Avoid calling get_constant() which will try to allocate // unloaded constant. We need only constant's type. int index = s.get_constant_pool_index(); - constantTag tag = s.get_constant_pool_tag(index); - if (tag.is_long() || tag.is_double()) { + BasicType con_bt = s.get_basic_type_for_constant_at(index); + if (con_bt == T_LONG || con_bt == T_DOUBLE) { // Only longs and doubles use 2 stack slots. state.lpush(); - } else if (tag.basic_type() == T_OBJECT) { + } else if (con_bt == T_OBJECT) { state.apush(unknown_obj); } else { state.spush(); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/ci/ciConstant.hpp openjdk-17-17.0.4+8/src/hotspot/share/ci/ciConstant.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/ci/ciConstant.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/ci/ciConstant.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -127,6 +127,17 @@ bool is_valid() const { return basic_type() != T_ILLEGAL; } + + bool is_loaded() const { + if (is_valid()) { + if (is_reference_type(basic_type())) { + return as_object()->is_loaded(); + } else { + return true; + } + } + return false; + } // Debugging output void print(); }; diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/ci/ciEnv.cpp openjdk-17-17.0.4+8/src/hotspot/share/ci/ciEnv.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/ci/ciEnv.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/ci/ciEnv.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -432,13 +432,6 @@ domain = Handle(current, accessing_klass->protection_domain()); } - // setup up the proper type to return on OOM - ciKlass* fail_type; - if (sym->char_at(0) == JVM_SIGNATURE_ARRAY) { - fail_type = _unloaded_ciobjarrayklass; - } else { - fail_type = _unloaded_ciinstance_klass; - } Klass* found_klass; { ttyUnlocker ttyul; // release tty lock to avoid ordering problems @@ -520,7 +513,6 @@ int index, bool& is_accessible, ciInstanceKlass* accessor) { - EXCEPTION_CONTEXT; Klass* klass = NULL; Symbol* klass_name = NULL; @@ -528,7 +520,7 @@ klass_name = cpool->symbol_at(index); } else { // Check if it's resolved if it's not a symbol constant pool entry. - klass = ConstantPool::klass_at_if_loaded(cpool, index); + klass = ConstantPool::klass_at_if_loaded(cpool, index); // Try to look it up by name. if (klass == NULL) { klass_name = cpool->klass_name_at(index); @@ -587,8 +579,6 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, int pool_index, int cache_index, ciInstanceKlass* accessor) { - bool ignore_will_link; - EXCEPTION_CONTEXT; int index = pool_index; if (cache_index >= 0) { assert(index < 0, "only one kind of index at a time"); @@ -599,12 +589,14 @@ return ciConstant(T_OBJECT, get_object(NULL)); } BasicType bt = T_OBJECT; - if (cpool->tag_at(index).is_dynamic_constant()) + if (cpool->tag_at(index).is_dynamic_constant()) { bt = Signature::basic_type(cpool->uncached_signature_ref_at(index)); - if (is_reference_type(bt)) { - } else { + } + if (!is_reference_type(bt)) { // we have to unbox the primitive value - if (!is_java_primitive(bt)) return ciConstant(); + if (!is_java_primitive(bt)) { + return ciConstant(); + } jvalue value; BasicType bt2 = java_lang_boxing_object::get_value(obj, &value); assert(bt2 == bt, ""); @@ -639,6 +631,7 @@ } else if (tag.is_double()) { return ciConstant((jdouble)cpool->double_at(index)); } else if (tag.is_string()) { + EXCEPTION_CONTEXT; oop string = NULL; assert(cache_index >= 0, "should have a cache index"); string = cpool->string_at(index, cache_index, THREAD); @@ -655,25 +648,22 @@ return ciConstant(T_OBJECT, constant); } } else if (tag.is_unresolved_klass_in_error()) { - return ciConstant(); + return ciConstant(T_OBJECT, get_unloaded_klass_mirror(NULL)); } else if (tag.is_klass() || tag.is_unresolved_klass()) { - // 4881222: allow ldc to take a class type - ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - record_out_of_memory_failure(); - return ciConstant(); - } + bool will_link; + ciKlass* klass = get_klass_by_index_impl(cpool, index, will_link, accessor); assert (klass->is_instance_klass() || klass->is_array_klass(), "must be an instance or array klass "); - return ciConstant(T_OBJECT, klass->java_mirror()); - } else if (tag.is_method_type()) { + ciInstance* mirror = (will_link ? klass->java_mirror() : get_unloaded_klass_mirror(klass)); + return ciConstant(T_OBJECT, mirror); + } else if (tag.is_method_type() || tag.is_method_type_in_error()) { // must execute Java code to link this CP entry into cache[i].f1 ciSymbol* signature = get_symbol(cpool->method_type_signature_at(index)); ciObject* ciobj = get_unloaded_method_type_constant(signature); return ciConstant(T_OBJECT, ciobj); - } else if (tag.is_method_handle()) { + } else if (tag.is_method_handle() || tag.is_method_handle_in_error()) { // must execute Java code to link this CP entry into cache[i].f1 + bool ignore_will_link; int ref_kind = cpool->method_handle_ref_kind_at(index); int callee_index = cpool->method_handle_klass_index_at(index); ciKlass* callee = get_klass_by_index_impl(cpool, callee_index, ignore_will_link, accessor); @@ -681,10 +671,10 @@ ciSymbol* signature = get_symbol(cpool->method_handle_signature_ref_at(index)); ciObject* ciobj = get_unloaded_method_handle_constant(callee, name, signature, ref_kind); return ciConstant(T_OBJECT, ciobj); - } else if (tag.is_dynamic_constant()) { - return ciConstant(); + } else if (tag.is_dynamic_constant() || tag.is_dynamic_constant_in_error()) { + return ciConstant(); // not supported } else { - ShouldNotReachHere(); + assert(false, "unknown tag: %d (%s)", tag.value(), tag.internal_name()); return ciConstant(); } } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/ci/ciMethod.cpp openjdk-17-17.0.4+8/src/hotspot/share/ci/ciMethod.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/ci/ciMethod.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/ci/ciMethod.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -81,7 +81,6 @@ _max_stack = h_m->max_stack(); _max_locals = h_m->max_locals(); _code_size = h_m->code_size(); - _intrinsic_id = h_m->intrinsic_id(); _handler_count = h_m->exception_table_length(); _size_of_parameters = h_m->size_of_parameters(); _uses_monitors = h_m->access_flags().has_monitor_bytecodes(); @@ -101,6 +100,10 @@ _bcea = NULL; #endif // COMPILER2 + // Check for blackhole intrinsic and then populate the intrinsic ID. + CompilerOracle::tag_blackhole_if_possible(h_m); + _intrinsic_id = h_m->intrinsic_id(); + ciEnv *env = CURRENT_ENV; if (env->jvmti_can_hotswap_or_post_breakpoint()) { // 6328518 check hotswap conditions under the right lock. @@ -154,8 +157,6 @@ ciReplay::initialize(this); } #endif - - CompilerOracle::tag_blackhole_if_possible(h_m); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/ci/ciStreams.cpp openjdk-17-17.0.4+8/src/hotspot/share/ci/ciStreams.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/ci/ciStreams.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/ci/ciStreams.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -252,6 +252,14 @@ } // ------------------------------------------------------------------ +// ciBytecodeStream::get_basic_type_for_constant_at +// +BasicType ciBytecodeStream::get_basic_type_for_constant_at(int index) const { + VM_ENTRY_MARK; + return _method->get_Method()->constants()->basic_type_for_constant_at(index); +} + +// ------------------------------------------------------------------ // ciBytecodeStream::get_field_index // // If this is a field access bytecode, get the constant pool @@ -476,8 +484,9 @@ constantPoolHandle cpool(THREAD, _method->get_Method()->constants()); bool ignore; // report as MethodHandle for invokedynamic, which is syntactically classless - if (cur_bc() == Bytecodes::_invokedynamic) - return CURRENT_ENV->get_klass_by_name(_holder, ciSymbols::java_lang_invoke_MethodHandle(), false); + if (cur_bc() == Bytecodes::_invokedynamic) { + return CURRENT_ENV->MethodHandle_klass(); + } return CURRENT_ENV->get_klass_by_index(cpool, get_method_holder_index(), ignore, _holder); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/ci/ciStreams.hpp openjdk-17-17.0.4+8/src/hotspot/share/ci/ciStreams.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/ci/ciStreams.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/ci/ciStreams.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -140,7 +140,7 @@ bool is_wide() const { return ( _pc == _was_wide ); } - // Does this instruction contain an index which refes into the CP cache? + // Does this instruction contain an index which refers into the CP cache? bool has_cache_index() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); } int get_index_u1() const { @@ -224,8 +224,9 @@ // constant. Do not attempt to resolve it, since that would require // execution of Java code. If it is not resolved, return an unloaded // object (ciConstant.as_object()->is_loaded() == false). - ciConstant get_constant(); + ciConstant get_constant(); constantTag get_constant_pool_tag(int index) const; + BasicType get_basic_type_for_constant_at(int index) const; // True if the klass-using bytecode points to an unresolved klass bool is_unresolved_klass() const { @@ -233,9 +234,17 @@ return tag.is_unresolved_klass(); } - bool is_unresolved_klass_in_error() const { - constantTag tag = get_constant_pool_tag(get_klass_index()); - return tag.is_unresolved_klass_in_error(); + bool is_in_error() const { + assert(cur_bc() == Bytecodes::_ldc || + cur_bc() == Bytecodes::_ldc_w || + cur_bc() == Bytecodes::_ldc2_w, "not supported: %s", Bytecodes::name(cur_bc())); + + int index = get_constant_pool_index(); + constantTag tag = get_constant_pool_tag(index); + return tag.is_unresolved_klass_in_error() || + tag.is_method_handle_in_error() || + tag.is_method_type_in_error() || + tag.is_dynamic_constant_in_error(); } // If this bytecode is one of get_field, get_static, put_field, diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/ci/ciTypeFlow.cpp openjdk-17-17.0.4+8/src/hotspot/share/ci/ciTypeFlow.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/ci/ciTypeFlow.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/ci/ciTypeFlow.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -720,6 +720,11 @@ // ------------------------------------------------------------------ // ciTypeFlow::StateVector::do_ldc void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { + if (str->is_in_error()) { + trap(str, NULL, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, + Deoptimization::Action_none)); + return; + } ciConstant con = str->get_constant(); if (con.is_valid()) { BasicType basic_type = con.basic_type(); @@ -735,14 +740,10 @@ push_translate(ciType::make(basic_type)); } } else { - if (str->is_unresolved_klass_in_error()) { - trap(str, NULL, Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, - Deoptimization::Action_none)); - } else { - // OutOfMemoryError in the CI while loading constant - push_null(); - outer()->record_failure("ldc did not link"); - } + // OutOfMemoryError in the CI while loading constant. + // Unresolved condy also lands here (not yet supported). + push_null(); + outer()->record_failure("ldc did not link"); } } @@ -2173,7 +2174,7 @@ case Bytecodes::_ldc: case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: - return str.is_unresolved_klass_in_error(); + return str.is_in_error(); case Bytecodes::_aload_0: // These bytecodes can trap for rewriting. We need to assume that diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/classfile/javaClasses.cpp openjdk-17-17.0.4+8/src/hotspot/share/classfile/javaClasses.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/classfile/javaClasses.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/classfile/javaClasses.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -4119,11 +4119,20 @@ void java_lang_invoke_MethodType::print_signature(oop mt, outputStream* st) { st->print("("); objArrayOop pts = ptypes(mt); - for (int i = 0, limit = pts->length(); i < limit; i++) { - java_lang_Class::print_signature(pts->obj_at(i), st); + if (pts != NULL) { + for (int i = 0, limit = pts->length(); i < limit; i++) { + java_lang_Class::print_signature(pts->obj_at(i), st); + } + } else { + st->print("NULL"); } st->print(")"); - java_lang_Class::print_signature(rtype(mt), st); + oop rt = rtype(mt); + if (rt != NULL) { + java_lang_Class::print_signature(rt, st); + } else { + st->print("NULL"); + } } Symbol* java_lang_invoke_MethodType::as_signature(oop mt, bool intern_if_not_found) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/classfile/systemDictionary.cpp openjdk-17-17.0.4+8/src/hotspot/share/classfile/systemDictionary.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/classfile/systemDictionary.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/classfile/systemDictionary.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -2013,8 +2013,9 @@ spe = NULL; // Must create lots of stuff here, but outside of the SystemDictionary lock. m = Method::make_method_handle_intrinsic(iid, signature, CHECK_NULL); - if (!Arguments::is_interpreter_only()) { + if (!Arguments::is_interpreter_only() || iid == vmIntrinsics::_linkToNative) { // Generate a compiled form of the MH intrinsic. + // linkToNative doesn't have interpreter-specific implementation, so always has to go through compiled version. AdapterHandlerLibrary::create_native_wrapper(m); // Check if have the compiled code. if (!m->has_compiled_code()) { @@ -2077,9 +2078,9 @@ Method* SystemDictionary::find_method_handle_invoker(Klass* klass, Symbol* name, Symbol* signature, - Klass* accessing_klass, - Handle *appendix_result, - TRAPS) { + Klass* accessing_klass, + Handle* appendix_result, + TRAPS) { assert(THREAD->can_call_java() ,""); Handle method_type = SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_NULL); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/code/codeCache.cpp openjdk-17-17.0.4+8/src/hotspot/share/code/codeCache.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/code/codeCache.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/code/codeCache.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -487,7 +487,7 @@ */ CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool handle_alloc_failure, int orig_code_blob_type) { // Possibly wakes up the sweeper thread. - NMethodSweeper::report_allocation(code_blob_type); + NMethodSweeper::report_allocation(); assert_locked_or_safepoint(CodeCache_lock); assert(size > 0, "Code cache allocation request must be > 0 but is %d", size); if (size <= 0) { @@ -512,7 +512,7 @@ // Fallback solution: Try to store code in another code heap. // NonNMethod -> MethodNonProfiled -> MethodProfiled (-> MethodNonProfiled) // Note that in the sweeper, we check the reverse_free_ratio of the code heap - // and force stack scanning if less than 10% of the code heap are free. + // and force stack scanning if less than 10% of the entire code cache are free. int type = code_blob_type; switch (type) { case CodeBlobType::NonNMethod: @@ -889,20 +889,17 @@ return max_cap; } -/** - * Returns the reverse free ratio. E.g., if 25% (1/4) of the code heap - * is free, reverse_free_ratio() returns 4. - */ -double CodeCache::reverse_free_ratio(int code_blob_type) { - CodeHeap* heap = get_code_heap(code_blob_type); - if (heap == NULL) { - return 0; - } - double unallocated_capacity = MAX2((double)heap->unallocated_capacity(), 1.0); // Avoid division by 0; - double max_capacity = (double)heap->max_capacity(); - double result = max_capacity / unallocated_capacity; - assert (max_capacity >= unallocated_capacity, "Must be"); +// Returns the reverse free ratio. E.g., if 25% (1/4) of the code cache +// is free, reverse_free_ratio() returns 4. +// Since code heap for each type of code blobs falls forward to the next +// type of code heap, return the reverse free ratio for the entire +// code cache. +double CodeCache::reverse_free_ratio() { + double unallocated = MAX2((double)unallocated_capacity(), 1.0); // Avoid division by 0; + double max = (double)max_capacity(); + double result = max / unallocated; + assert (max >= unallocated, "Must be"); assert (result >= 1.0, "reverse_free_ratio must be at least 1. It is %f", result); return result; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/code/codeCache.hpp openjdk-17-17.0.4+8/src/hotspot/share/code/codeCache.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/code/codeCache.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/code/codeCache.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,7 +211,7 @@ static size_t unallocated_capacity(); static size_t max_capacity(); - static double reverse_free_ratio(int code_blob_type); + static double reverse_free_ratio(); static void clear_inline_caches(); // clear all inline caches static void cleanup_inline_caches(); // clean unloaded/zombie nmethods from inline caches diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/code/codeHeapState.cpp openjdk-17-17.0.4+8/src/hotspot/share/code/codeHeapState.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/code/codeHeapState.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/code/codeHeapState.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -755,18 +755,17 @@ CodeBlob* cb = (CodeBlob*)heap->find_start(h); cbType = get_cbType(cb); // Will check for cb == NULL and other safety things. if (cbType != noType) { - const char* blob_name = os::strdup(cb->name()); + const char* blob_name = nullptr; unsigned int nm_size = 0; int temperature = 0; nmethod* nm = cb->as_nmethod_or_null(); if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb. ResourceMark rm; Method* method = nm->method(); - if (nm->is_in_use()) { - blob_name = os::strdup(method->name_and_sig_as_C_string()); - } - if (nm->is_not_entrant()) { + if (nm->is_in_use() || nm->is_not_entrant()) { blob_name = os::strdup(method->name_and_sig_as_C_string()); + } else { + blob_name = os::strdup(cb->name()); } nm_size = nm->total_size(); @@ -814,6 +813,8 @@ default: break; } + } else { + blob_name = os::strdup(cb->name()); } //------------------------------------------ diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/compiler/compilationPolicy.cpp openjdk-17-17.0.4+8/src/hotspot/share/compiler/compilationPolicy.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/compiler/compilationPolicy.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/compiler/compilationPolicy.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -315,7 +315,7 @@ // The main intention is to keep enough free space for C2 compiled code // to achieve peak performance if the code cache is under stress. if (CompilerConfig::is_tiered() && !CompilationModeFlag::disable_intermediate() && is_c1_compile(level)) { - double current_reverse_free_ratio = CodeCache::reverse_free_ratio(CodeCache::get_code_blob_type(level)); + double current_reverse_free_ratio = CodeCache::reverse_free_ratio(); if (current_reverse_free_ratio > _increase_threshold_at_ratio) { k *= exp(current_reverse_free_ratio - _increase_threshold_at_ratio); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/compiler/compileBroker.cpp openjdk-17-17.0.4+8/src/hotspot/share/compiler/compileBroker.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/compiler/compileBroker.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/compiler/compileBroker.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -224,11 +224,13 @@ } void log_metaspace_failure(const char* reason) { + // Note: This method can be called from non-Java/compiler threads to + // log the global metaspace failure that might affect profiling. ResourceMark rm; StringLogMessage lm; lm.print("%4d COMPILE PROFILING SKIPPED: %s", -1, reason); lm.print("\n"); - log(JavaThread::current(), "%s", (const char*)lm); + log(Thread::current(), "%s", (const char*)lm); } }; @@ -1990,6 +1992,8 @@ method->clear_queued_for_compilation(); task->set_failure_reason("compilation is disabled"); } + } else { + task->set_failure_reason("breakpoints are present"); } if (UseDynamicNumberOfCompilerThreads) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/compiler/compilerDefinitions.cpp openjdk-17-17.0.4+8/src/hotspot/share/compiler/compilerDefinitions.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/compiler/compilerDefinitions.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/compiler/compilerDefinitions.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -124,10 +124,17 @@ // Returns threshold scaled with the value of scale. // If scale < 0.0, threshold is returned without scaling. intx CompilerConfig::scaled_compile_threshold(intx threshold, double scale) { + assert(threshold >= 0, "must be"); if (scale == 1.0 || scale < 0.0) { return threshold; } else { - return (intx)(threshold * scale); + double v = threshold * scale; + assert(v >= 0, "must be"); + if (v > max_intx) { + return max_intx; + } else { + return (intx)(v); + } } } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/interpreter/bootstrapInfo.cpp openjdk-17-17.0.4+8/src/hotspot/share/interpreter/bootstrapInfo.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/interpreter/bootstrapInfo.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/interpreter/bootstrapInfo.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -67,7 +67,7 @@ if (!cpce->is_f1_null()) { methodHandle method( THREAD, cpce->f1_as_method()); Handle appendix( THREAD, cpce->appendix_if_resolved(_pool)); - result.set_handle(method, appendix, THREAD); + result.set_handle(vmClasses::MethodHandle_klass(), method, appendix, THREAD); Exceptions::wrap_dynamic_exception(/* is_indy */ true, CHECK_false); return true; } else if (cpce->indy_resolution_failed()) { @@ -221,7 +221,7 @@ void BootstrapInfo::resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS) { assert(is_resolved(), ""); - result.set_handle(resolved_method(), resolved_appendix(), CHECK); + result.set_handle(vmClasses::MethodHandle_klass(), resolved_method(), resolved_appendix(), CHECK); } void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/interpreter/linkResolver.cpp openjdk-17-17.0.4+8/src/hotspot/share/interpreter/linkResolver.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/interpreter/linkResolver.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/interpreter/linkResolver.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -94,11 +94,6 @@ assert(!resolved_method->is_compiled_lambda_form(), "these must be handled via an invokehandle call"); } -void CallInfo::set_handle(const methodHandle& resolved_method, - Handle resolved_appendix, TRAPS) { - set_handle(vmClasses::MethodHandle_klass(), resolved_method, resolved_appendix, CHECK); -} - void CallInfo::set_handle(Klass* resolved_klass, const methodHandle& resolved_method, Handle resolved_appendix, TRAPS) { @@ -476,14 +471,12 @@ } Handle appendix; - Handle method_type; - Method* result = SystemDictionary::find_method_handle_invoker( - klass, - name, - full_signature, - link_info.current_klass(), - &appendix, - CHECK_NULL); + Method* result = SystemDictionary::find_method_handle_invoker(klass, + name, + full_signature, + link_info.current_klass(), + &appendix, + CHECK_NULL); if (lt_mh.is_enabled()) { LogStream ls(lt_mh); ls.print("lookup_polymorphic_method => (via Java) "); @@ -621,7 +614,7 @@ Klass* resolved_klass = link_info.resolved_klass(); if (pool->has_preresolution() - || (resolved_klass == vmClasses::MethodHandle_klass() && + || ((resolved_klass == vmClasses::MethodHandle_klass() || resolved_klass == vmClasses::VarHandle_klass()) && MethodHandles::is_signature_polymorphic_name(resolved_klass, link_info.name()))) { Method* result = ConstantPool::method_at_if_loaded(pool, index); if (result != NULL) { @@ -1679,15 +1672,31 @@ resolve_interface_call(result, recv, recvrKlass, link_info, true, CHECK); } +bool LinkResolver::resolve_previously_linked_invokehandle(CallInfo& result, const LinkInfo& link_info, const constantPoolHandle& pool, int index, TRAPS) { + int cache_index = ConstantPool::decode_cpcache_index(index, true); + ConstantPoolCacheEntry* cpce = pool->cache()->entry_at(cache_index); + if (!cpce->is_f1_null()) { + Klass* resolved_klass = link_info.resolved_klass(); + methodHandle method(THREAD, cpce->f1_as_method()); + Handle appendix(THREAD, cpce->appendix_if_resolved(pool)); + result.set_handle(resolved_klass, method, appendix, CHECK_false); + return true; + } else { + return false; + } +} void LinkResolver::resolve_invokehandle(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { - // This guy is reached from InterpreterRuntime::resolve_invokehandle. LinkInfo link_info(pool, index, CHECK); if (log_is_enabled(Info, methodhandles)) { ResourceMark rm(THREAD); log_info(methodhandles)("resolve_invokehandle %s %s", link_info.name()->as_C_string(), link_info.signature()->as_C_string()); } + { // Check if the call site has been bound already, and short circuit: + bool is_done = resolve_previously_linked_invokehandle(result, link_info, pool, index, CHECK); + if (is_done) return; + } resolve_handle_call(result, link_info, CHECK); } @@ -1699,9 +1708,32 @@ assert(resolved_klass == vmClasses::MethodHandle_klass() || resolved_klass == vmClasses::VarHandle_klass(), ""); assert(MethodHandles::is_signature_polymorphic_name(link_info.name()), ""); - Handle resolved_appendix; - Method* resolved_method = lookup_polymorphic_method(link_info, &resolved_appendix, CHECK); - result.set_handle(resolved_klass, methodHandle(THREAD, resolved_method), resolved_appendix, CHECK); + Handle resolved_appendix; + Method* m = lookup_polymorphic_method(link_info, &resolved_appendix, CHECK); + methodHandle resolved_method(THREAD, m); + + if (link_info.check_access()) { + Symbol* name = link_info.name(); + vmIntrinsics::ID iid = MethodHandles::signature_polymorphic_name_id(name); + if (MethodHandles::is_signature_polymorphic_intrinsic(iid)) { + // Check if method can be accessed by the referring class. + // MH.linkTo* invocations are not rewritten to invokehandle. + assert(iid == vmIntrinsicID::_invokeBasic, "%s", vmIntrinsics::name_at(iid)); + + Klass* current_klass = link_info.current_klass(); + assert(current_klass != NULL , "current_klass should not be null"); + check_method_accessability(current_klass, + resolved_klass, + resolved_method->method_holder(), + resolved_method, + CHECK); + } else { + // Java code is free to arbitrarily link signature-polymorphic invokers. + assert(iid == vmIntrinsics::_invokeGeneric, "not an invoker: %s", vmIntrinsics::name_at(iid)); + assert(MethodHandles::is_signature_polymorphic_public_name(resolved_klass, name), "not public"); + } + } + result.set_handle(resolved_klass, resolved_method, resolved_appendix, CHECK); } void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int indy_index, TRAPS) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/interpreter/linkResolver.hpp openjdk-17-17.0.4+8/src/hotspot/share/interpreter/linkResolver.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/interpreter/linkResolver.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/interpreter/linkResolver.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -66,8 +66,6 @@ const methodHandle& resolved_method, const methodHandle& selected_method, int vtable_index, TRAPS); - void set_handle(const methodHandle& resolved_method, - Handle resolved_appendix, TRAPS); void set_handle(Klass* resolved_klass, const methodHandle& resolved_method, Handle resolved_appendix, TRAPS); @@ -249,6 +247,11 @@ Klass* recv_klass, bool check_null_and_abstract, TRAPS); + static bool resolve_previously_linked_invokehandle(CallInfo& result, + const LinkInfo& link_info, + const constantPoolHandle& pool, + int index, TRAPS); + static void check_field_accessability(Klass* ref_klass, Klass* resolved_klass, Klass* sel_klass, @@ -337,7 +340,6 @@ const methodHandle& attached_method, Bytecodes::Code byte, TRAPS); - public: // Only resolved method known. static void throw_abstract_method_error(const methodHandle& resolved_method, TRAPS) { throw_abstract_method_error(resolved_method, methodHandle(), NULL, CHECK); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp openjdk-17-17.0.4+8/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -2548,6 +2548,8 @@ SET_STACK_OBJECT(ts->earlyret_oop(), 0); MORE_STACK(1); break; + default: + ShouldNotReachHere(); } ts->clr_earlyret_value(); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp openjdk-17-17.0.4+8/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -549,14 +549,16 @@ void JfrJavaSupport::abort(jstring errorMsg, JavaThread* t) { DEBUG_ONLY(check_java_thread_in_vm(t)); - ResourceMark rm(t); - const char* const error_msg = c_str(errorMsg, t); - if (error_msg != NULL) { - log_error(jfr, system)("%s",error_msg); + abort(c_str(errorMsg, t)); +} + +void JfrJavaSupport::abort(const char* error_msg, bool dump_core /* true */) { + if (error_msg != nullptr) { + log_error(jfr, system)("%s", error_msg); } log_error(jfr, system)("%s", "An irrecoverable error in Jfr. Shutting down VM..."); - vm_abort(); + vm_abort(dump_core); } JfrJavaSupport::CAUSE JfrJavaSupport::_cause = JfrJavaSupport::VM_ERROR; diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp openjdk-17-17.0.4+8/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * 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,6 +100,7 @@ // critical static void abort(jstring errorMsg, TRAPS); + static void abort(const char* error_msg, bool dump_core = true); static void uncaught_exception(jthrowable throwable, JavaThread* t); // asserts diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp openjdk-17-17.0.4+8/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * 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,17 @@ _next(next) { } +BitSet::BitMapFragmentTable::~BitMapFragmentTable() { + for (int index = 0; index < table_size(); index ++) { + Entry* e = bucket(index); + while (e != nullptr) { + Entry* tmp = e; + e = e->next(); + free_entry(tmp); + } + } +} + BitSet::BitSet() : _bitmap_fragments(32), _fragment_list(NULL), diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jfr/leakprofiler/chains/bitset.hpp openjdk-17-17.0.4+8/src/hotspot/share/jfr/leakprofiler/chains/bitset.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/jfr/leakprofiler/chains/bitset.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jfr/leakprofiler/chains/bitset.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,6 +68,7 @@ public: BitMapFragmentTable(int table_size) : BasicHashtable(table_size, sizeof(Entry)) {} + ~BitMapFragmentTable(); void add(uintptr_t key, CHeapBitMap* value); CHeapBitMap** lookup(uintptr_t key); }; diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp openjdk-17-17.0.4+8/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -612,11 +612,11 @@ assert(store != NULL, "invariant"); assert(!store->is_empty(), "invariant"); register_serializers(); - sample_infos = NULL; - ref_infos = NULL; - array_infos = NULL; - field_infos = NULL; - root_infos = NULL; + assert(field_infos == NULL, "Invariant"); + assert(sample_infos == NULL, "Invariant"); + assert(ref_infos == NULL, "Invariant"); + assert(array_infos == NULL, "Invariant"); + assert(root_infos == NULL, "Invariant"); } ObjectSampleWriter::~ObjectSampleWriter() { @@ -625,6 +625,16 @@ write_array_infos(_writer); write_field_infos(_writer); write_root_descriptors(_writer); + + // Followings are RA allocated, memory will be released automatically. + if (field_infos != NULL) { + field_infos->~FieldTable(); + field_infos = NULL; + } + sample_infos = NULL; + ref_infos = NULL; + array_infos = NULL; + root_infos = NULL; } bool ObjectSampleWriter::operator()(StoredEdge& e) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp openjdk-17-17.0.4+8/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP #define SHARE_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP +#include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/writers/jfrStreamWriterHost.hpp" - #include "runtime/os.hpp" template @@ -77,6 +77,9 @@ while (len > 0) { const unsigned int nBytes = len > INT_MAX ? INT_MAX : (unsigned int)len; const ssize_t num_written = (ssize_t)os::write(_fd, buf, nBytes); + if (errno == ENOSPC) { + JfrJavaSupport::abort("Failed to write to jfr stream because no space left on device", false); + } guarantee(num_written > 0, "Nothing got written, or os::write() failed"); _stream_pos += num_written; len -= num_written; diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2339,7 +2339,7 @@ } C2V_END -C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle)) +C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jboolean callPostTranslation)) requireJVMCINativeLibrary(JVMCI_CHECK_0); if (obj_handle == NULL) { return 0L; @@ -2390,7 +2390,9 @@ const char* cstring = name_string.is_null() ? NULL : thisEnv->as_utf8_string(name_string); // Create a new HotSpotNmethod instance in the peer runtime result = peerEnv->new_HotSpotNmethod(mh, cstring, isDefault, compileIdSnapshot, JVMCI_CHECK_0); - if (nm == NULL) { + if (result.is_null()) { + // exception occurred (e.g. OOME) creating a new HotSpotNmethod + } else if (nm == NULL) { // nmethod must have been unloaded } else { // Link the new HotSpotNmethod to the nmethod @@ -2413,6 +2415,13 @@ JVMCI_THROW_MSG_0(IllegalArgumentException, err_msg("Cannot translate object of type: %s", thisEnv->klass_name(obj))); } + if (callPostTranslation) { + peerEnv->call_HotSpotJVMCIRuntime_postTranslation(result, JVMCI_CHECK_0); + } + // Propagate any exception that occurred while creating the translated object + if (peerEnv->transfer_pending_exception(thread, thisEnv)) { + return 0L; + } return (jlong) peerEnv->make_global(result).as_jobject(); } @@ -2710,7 +2719,7 @@ {CC "getCurrentJavaThread", CC "()J", FN_PTR(getCurrentJavaThread)}, {CC "attachCurrentThread", CC "([BZ)Z", FN_PTR(attachCurrentThread)}, {CC "detachCurrentThread", CC "()V", FN_PTR(detachCurrentThread)}, - {CC "translate", CC "(" OBJECT ")J", FN_PTR(translate)}, + {CC "translate", CC "(" OBJECT "Z)J", FN_PTR(translate)}, {CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)}, {CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)}, {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciEnv.cpp openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciEnv.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciEnv.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciEnv.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -278,35 +278,141 @@ } } -void JVMCIEnv::translate_hotspot_exception_to_jni_exception(JavaThread* THREAD, const Handle& throwable) { - assert(!is_hotspot(), "must_be"); - // Resolve HotSpotJVMCIRuntime class explicitly as HotSpotJVMCI::compute_offsets - // may not have been called. - Klass* runtimeKlass = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_hotspot_HotSpotJVMCIRuntime(), true, CHECK); - JavaCallArguments jargs; - jargs.push_oop(throwable); - JavaValue result(T_OBJECT); - JavaCalls::call_static(&result, - runtimeKlass, - vmSymbols::encodeThrowable_name(), - vmSymbols::encodeThrowable_signature(), &jargs, THREAD); - if (HAS_PENDING_EXCEPTION) { - JVMCIRuntime::fatal_exception(this, "HotSpotJVMCIRuntime.encodeThrowable should not throw an exception"); +// Shared code for translating an exception from HotSpot to libjvmci or vice versa. +class ExceptionTranslation: public StackObj { + protected: + JVMCIEnv* _from_env; // Source of translation. Can be nullptr. + JVMCIEnv* _to_env; // Destination of translation. Never nullptr. + + ExceptionTranslation(JVMCIEnv* from_env, JVMCIEnv* to_env) : _from_env(from_env), _to_env(to_env) {} + + // Encodes the exception in `_from_env` into `buffer`. + // Where N is the number of bytes needed for the encoding, returns N if N <= `buffer_size` + // and the encoding was written to `buffer` otherwise returns -N. + virtual int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) = 0; + + // Decodes the exception in `buffer` in `_to_env` and throws it. + virtual void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) = 0; + + public: + void doit(JavaThread* THREAD) { + // Resolve HotSpotJVMCIRuntime class explicitly as HotSpotJVMCI::compute_offsets + // may not have been called. + Klass* runtimeKlass = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_hotspot_HotSpotJVMCIRuntime(), true, CHECK); + + int buffer_size = 2048; + while (true) { + ResourceMark rm; + jlong buffer = (jlong) NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, jbyte, buffer_size); + int res = encode(THREAD, runtimeKlass, buffer, buffer_size); + if ((_from_env != nullptr && _from_env->has_pending_exception()) || HAS_PENDING_EXCEPTION) { + JVMCIRuntime::fatal_exception(_from_env, "HotSpotJVMCIRuntime.encodeThrowable should not throw an exception"); + } + if (res < 0) { + int required_buffer_size = -res; + if (required_buffer_size > buffer_size) { + buffer_size = required_buffer_size; + } + } else { + decode(THREAD, runtimeKlass, buffer); + if (!_to_env->has_pending_exception()) { + JVMCIRuntime::fatal_exception(_to_env, "HotSpotJVMCIRuntime.decodeAndThrowThrowable should throw an exception"); + } + return; + } + } } +}; - oop encoded_throwable_string = result.get_oop(); +// Translates an exception on the HotSpot heap to an exception on the shared library heap. +class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation { + private: + const Handle& _throwable; - ResourceMark rm; - const char* encoded_throwable_chars = java_lang_String::as_utf8_string(encoded_throwable_string); + int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) { + JavaCallArguments jargs; + jargs.push_oop(_throwable); + jargs.push_long(buffer); + jargs.push_int(buffer_size); + JavaValue result(T_INT); + JavaCalls::call_static(&result, + runtimeKlass, + vmSymbols::encodeThrowable_name(), + vmSymbols::encodeThrowable_signature(), &jargs, THREAD); + return result.get_jint(); + } + + void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) { + JNIAccessMark jni(_to_env, THREAD); + jni()->CallStaticVoidMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), + JNIJVMCI::HotSpotJVMCIRuntime::decodeAndThrowThrowable_method(), + buffer); + } + public: + HotSpotToSharedLibraryExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, const Handle& throwable) : + ExceptionTranslation(hotspot_env, jni_env), _throwable(throwable) {} +}; + +// Translates an exception on the shared library heap to an exception on the HotSpot heap. +class SharedLibraryToHotSpotExceptionTranslation : public ExceptionTranslation { + private: + jthrowable _throwable; + + int encode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer, int buffer_size) { + JNIAccessMark jni(_from_env, THREAD); + return jni()->CallStaticIntMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), + JNIJVMCI::HotSpotJVMCIRuntime::encodeThrowable_method(), + _throwable, buffer, buffer_size); + } - JNIAccessMark jni(this, THREAD); - jobject jni_encoded_throwable_string = jni()->NewStringUTF(encoded_throwable_chars); - jthrowable jni_throwable = (jthrowable) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), - JNIJVMCI::HotSpotJVMCIRuntime::decodeThrowable_method(), - jni_encoded_throwable_string); - jni()->Throw(jni_throwable); + void decode(JavaThread* THREAD, Klass* runtimeKlass, jlong buffer) { + JavaCallArguments jargs; + jargs.push_long(buffer); + JavaValue result(T_VOID); + JavaCalls::call_static(&result, + runtimeKlass, + vmSymbols::decodeAndThrowThrowable_name(), + vmSymbols::long_void_signature(), &jargs, THREAD); + } + public: + SharedLibraryToHotSpotExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, jthrowable throwable) : + ExceptionTranslation(jni_env, hotspot_env), _throwable(throwable) {} +}; + +void JVMCIEnv::translate_to_jni_exception(JavaThread* THREAD, const Handle& throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) { + HotSpotToSharedLibraryExceptionTranslation(hotspot_env, jni_env, throwable).doit(THREAD); } +void JVMCIEnv::translate_from_jni_exception(JavaThread* THREAD, jthrowable throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) { + SharedLibraryToHotSpotExceptionTranslation(hotspot_env, jni_env, throwable).doit(THREAD); +} + +jboolean JVMCIEnv::transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env) { + if (is_hotspot()) { + if (HAS_PENDING_EXCEPTION) { + Handle throwable = Handle(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + translate_to_jni_exception(THREAD, throwable, this, peer_env); + return true; + } + } else { + jthrowable ex = nullptr; + { + JNIAccessMark jni(this, THREAD); + ex = jni()->ExceptionOccurred(); + if (ex != nullptr) { + jni()->ExceptionClear(); + } + } + if (ex != nullptr) { + translate_from_jni_exception(THREAD, ex, peer_env, this); + return true; + } + } + return false; +} + + JVMCIEnv::~JVMCIEnv() { if (_throw_to_caller) { if (is_hotspot()) { @@ -318,7 +424,7 @@ if (HAS_PENDING_EXCEPTION) { Handle throwable = Handle(THREAD, PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; - translate_hotspot_exception_to_jni_exception(THREAD, throwable); + translate_to_jni_exception(THREAD, throwable, nullptr, this); } } } @@ -801,6 +907,23 @@ } } +void JVMCIEnv::call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCIEnv* JVMCIENV) { + JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. + if (is_hotspot()) { + JavaCallArguments jargs; + jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(object))); + JavaValue result(T_VOID); + JavaCalls::call_static(&result, + HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), + vmSymbols::postTranslation_name(), + vmSymbols::object_void_signature(), &jargs, CHECK); + } else { + JNIAccessMark jni(this, THREAD); + jni()->CallStaticVoidMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), + JNIJVMCI::HotSpotJVMCIRuntime::postTranslation_method(), + object.as_jobject()); + } +} JVMCIObject JVMCIEnv::call_JavaConstant_forPrimitive(JVMCIObject kind, jlong value, JVMCI_TRAPS) { JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciEnv.hpp openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciEnv.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciEnv.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciEnv.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -171,11 +171,15 @@ const char* _file; // The file and ... int _line; // ... line where this JNIEnv was created - // Translates an exception on the HotSpot heap to an exception on - // the shared library heap. The translation includes the stack and - // causes of `throwable`. The translated exception is pending in the - // shared library thread upon returning. - void translate_hotspot_exception_to_jni_exception(JavaThread* THREAD, const Handle& throwable); + // Translates an exception on the HotSpot heap (i.e., hotspot_env) to an exception on + // the shared library heap (i.e., jni_env). The translation includes the stack and cause(s) of `throwable`. + // The translated exception is pending in jni_env upon returning. + static void translate_to_jni_exception(JavaThread* THREAD, const Handle& throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env); + + // Translates an exception on the shared library heap (i.e., jni_env) to an exception on + // the HotSpot heap (i.e., hotspot_env). The translation includes the stack and cause(s) of `throwable`. + // The translated exception is pending in hotspot_env upon returning. + static void translate_from_jni_exception(JavaThread* THREAD, jthrowable throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env); public: // Opens a JVMCIEnv scope for a Java to VM call (e.g., via CompilerToVM). @@ -225,6 +229,11 @@ jboolean has_pending_exception(); void clear_pending_exception(); + // If this env has a pending exception, it is translated to be a pending + // exception in `peer_env` and is cleared from this env. Returns true + // if a pending exception was transferred, false otherwise. + jboolean transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env); + // Prints an exception and stack trace of a pending exception. void describe_pending_exception(bool clear); @@ -311,6 +320,8 @@ jboolean call_HotSpotJVMCIRuntime_isGCSupported(JVMCIObject runtime, jint gcIdentifier); + void call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCI_TRAPS); + BasicType kindToBasicType(JVMCIObject kind, JVMCI_TRAPS); #define DO_THROW(name) \ diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciJavaClasses.cpp openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciJavaClasses.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciJavaClasses.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciJavaClasses.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciJavaClasses.hpp openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciJavaClasses.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/jvmci/jvmciJavaClasses.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jvmci/jvmciJavaClasses.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -349,13 +349,14 @@ objectarray_field(HotSpotJVMCIRuntime, excludeFromJVMCICompilation, "[Ljava/lang/Module;") \ jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, compileMethod, compileMethod_signature, (JVMCIObject runtime, JVMCIObject method, int entry_bci, jlong env, int id)) \ jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, isGCSupported, int_bool_signature, (JVMCIObject runtime, int gcIdentifier)) \ - jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable)) \ - jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, decodeThrowable, decodeThrowable_signature, (JVMCIObject encodedThrowable)) \ + jvmci_method(CallStaticBooleanMethod, GetStaticMethodID, call_static, bool, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable, jlong buffer, int buffer_size)) \ + jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, decodeAndThrowThrowable, long_void_signature, (jlong buffer)) \ jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, bootstrapFinished, void_method_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \ jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, shutdown, void_method_signature, (JVMCIObject runtime)) \ jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, runtime, runtime_signature, (JVMCI_TRAPS)) \ jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, HotSpotJVMCIRuntime, getCompiler, getCompiler_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \ jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, callToString, callToString_signature, (JVMCIObject object, JVMCI_TRAPS)) \ + jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, postTranslation, object_void_signature, (JVMCIObject object, JVMCI_TRAPS)) \ end_class \ start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \ jvmci_constructor(JVMCIError, "(Ljava/lang/String;)V") \ diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp openjdk-17-17.0.4+8/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * 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,9 +105,8 @@ template(compileMethod_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;IJI)Ljdk/vm/ci/hotspot/HotSpotCompilationRequestResult;") \ template(isGCSupported_name, "isGCSupported") \ template(encodeThrowable_name, "encodeThrowable") \ - template(encodeThrowable_signature, "(Ljava/lang/Throwable;)Ljava/lang/String;") \ - template(decodeThrowable_name, "decodeThrowable") \ - template(decodeThrowable_signature, "(Ljava/lang/String;)Ljava/lang/Throwable;") \ + template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ + template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \ template(fromMetaspace_name, "fromMetaspace") \ template(method_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ template(constantPool_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;") \ @@ -123,6 +122,7 @@ template(getCompiler_signature, "()Ljdk/vm/ci/runtime/JVMCICompiler;") \ template(callToString_name, "callToString") \ template(callToString_signature, "(Ljava/lang/Object;)Ljava/lang/String;") \ + template(postTranslation_name, "postTranslation") \ template(getName_name, "getName") \ template(bootstrapFinished_name, "bootstrapFinished") \ template(forPrimitive_name, "forPrimitive") \ diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/logging/logConfiguration.cpp openjdk-17-17.0.4+8/src/hotspot/share/logging/logConfiguration.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/logging/logConfiguration.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/logging/logConfiguration.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -365,9 +365,9 @@ // Find the next colon or quote char* next = strpbrk(str, ":\""); #ifdef _WINDOWS - // Skip over Windows paths such as "C:\..." - // Handle both C:\... and file=C:\..." - if (next != NULL && next[0] == ':' && next[1] == '\\') { + // Skip over Windows paths such as "C:\..." and "C:/...". + // Handles both "C:\..." and "file=C:\...". + if (next != NULL && next[0] == ':' && (next[1] == '\\' || next[1] == '/')) { if (next == str + 1 || (strncmp(str, "file=", 5) == 0)) { next = strpbrk(next + 1, ":\""); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/logging/logOutput.cpp openjdk-17-17.0.4+8/src/hotspot/share/logging/logOutput.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/logging/logOutput.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/logging/logOutput.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -334,6 +334,11 @@ assert(n_deviates < deviating_tagsets, "deviating tag set array overflow"); assert(prev_deviates > n_deviates, "number of deviating tag sets must never grow"); + + if (n_deviates == 1 && n_selections == 0) { + // we're done as we couldn't reduce things any further + break; + } } FREE_C_HEAP_ARRAY(LogTagSet*, deviates); FREE_C_HEAP_ARRAY(Selection, selections); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/memory/universe.cpp openjdk-17-17.0.4+8/src/hotspot/share/memory/universe.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/memory/universe.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/memory/universe.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1236,6 +1236,7 @@ if (_fullgc_alot_dummy_next >= fullgc_alot_dummy_array->length()) { // No more dummies to release, release entire array instead _fullgc_alot_dummy_array.release(Universe::vm_global()); + _fullgc_alot_dummy_array = OopHandle(); // NULL out OopStorage pointer. return false; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/oops/constantPool.cpp openjdk-17-17.0.4+8/src/hotspot/share/oops/constantPool.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/oops/constantPool.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/oops/constantPool.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -884,11 +884,9 @@ constantTag ConstantPool::constant_tag_at(int which) { constantTag tag = tag_at(which); - if (tag.is_dynamic_constant() || - tag.is_dynamic_constant_in_error()) { + if (tag.is_dynamic_constant()) { BasicType bt = basic_type_for_constant_at(which); - // dynamic constant could return an array, treat as object - return constantTag::ofBasicType(is_reference_type(bt) ? T_OBJECT : bt); + return constantTag(constantTag::type2tag(bt)); } return tag; } @@ -975,7 +973,6 @@ switch (tag.value()) { case JVM_CONSTANT_UnresolvedClass: - case JVM_CONSTANT_UnresolvedClassInError: case JVM_CONSTANT_Class: { assert(cache_index == _no_index_sentinel, "should not have been set"); @@ -1043,14 +1040,6 @@ result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL); break; - case JVM_CONSTANT_DynamicInError: - case JVM_CONSTANT_MethodHandleInError: - case JVM_CONSTANT_MethodTypeInError: - { - throw_resolution_error(this_cp, index, CHECK_NULL); - break; - } - case JVM_CONSTANT_MethodHandle: { int ref_kind = this_cp->method_handle_ref_kind_at(index); @@ -1064,11 +1053,14 @@ callee_index, name->as_C_string(), signature->as_C_string()); } - Klass* callee = klass_at_impl(this_cp, callee_index, CHECK_NULL); + Klass* callee = klass_at_impl(this_cp, callee_index, THREAD); + if (HAS_PENDING_EXCEPTION) { + save_and_throw_exception(this_cp, index, tag, CHECK_NULL); + } // Check constant pool method consistency if ((callee->is_interface() && m_tag.is_method()) || - ((!callee->is_interface() && m_tag.is_interface_method()))) { + (!callee->is_interface() && m_tag.is_interface_method())) { ResourceMark rm(THREAD); stringStream ss; ss.print("Inconsistent constant pool data in classfile for class %s. " @@ -1080,17 +1072,18 @@ index, callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef", callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), "%s", ss.as_string()); + save_and_throw_exception(this_cp, index, tag, CHECK_NULL); } Klass* klass = this_cp->pool_holder(); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, THREAD); - result_oop = value(); if (HAS_PENDING_EXCEPTION) { save_and_throw_exception(this_cp, index, tag, CHECK_NULL); } + result_oop = value(); break; } @@ -1135,10 +1128,15 @@ result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL); break; + case JVM_CONSTANT_UnresolvedClassInError: + case JVM_CONSTANT_DynamicInError: + case JVM_CONSTANT_MethodHandleInError: + case JVM_CONSTANT_MethodTypeInError: + throw_resolution_error(this_cp, index, CHECK_NULL); + break; + default: - DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d", - this_cp(), index, cache_index, tag.value())); - assert(false, "unexpected constant tag"); + fatal("unexpected constant tag at CP %p[%d/%d] = %d", this_cp(), index, cache_index, tag.value()); break; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/oops/method.cpp openjdk-17-17.0.4+8/src/hotspot/share/oops/method.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/oops/method.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/oops/method.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1186,7 +1186,7 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { // If the code cache is full, we may reenter this function for the // leftover methods that weren't linked. - if (_i2i_entry != NULL) { + if (adapter() != NULL) { return; } assert( _code == NULL, "nothing compiled yet" ); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/arraycopynode.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/arraycopynode.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/arraycopynode.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/arraycopynode.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -189,9 +189,8 @@ } MergeMemNode* mem = phase->transform(MergeMemNode::make(in_mem))->as_MergeMem(); - PhaseIterGVN* igvn = phase->is_IterGVN(); - if (igvn != NULL) { - igvn->_worklist.push(mem); + if (can_reshape) { + phase->is_IterGVN()->_worklist.push(mem); } if (!inst_src->klass_is_exact()) { @@ -294,9 +293,17 @@ uint header = arrayOopDesc::base_offset_in_bytes(dest_elem); src_offset = Compile::conv_I2X_index(phase, src_offset, ary_src->size()); + if (src_offset->is_top()) { + // Offset is out of bounds (the ArrayCopyNode will be removed) + return false; + } dest_offset = Compile::conv_I2X_index(phase, dest_offset, ary_dest->size()); - if (src_offset->is_top() || dest_offset->is_top()) { + if (dest_offset->is_top()) { // Offset is out of bounds (the ArrayCopyNode will be removed) + if (can_reshape) { + // record src_offset, so it can be deleted later (if it is dead) + phase->is_IterGVN()->_worklist.push(src_offset); + } return false; } @@ -316,9 +323,6 @@ disjoint_bases = true; - adr_src = phase->transform(new AddPNode(base_src, base_src, src_offset)); - adr_dest = phase->transform(new AddPNode(base_dest, base_dest, dest_offset)); - BasicType elem = ary_src->klass()->as_array_klass()->element_type()->basic_type(); if (is_reference_type(elem)) { elem = T_OBJECT; @@ -329,6 +333,9 @@ return false; } + adr_src = phase->transform(new AddPNode(base_src, base_src, src_offset)); + adr_dest = phase->transform(new AddPNode(base_dest, base_dest, dest_offset)); + // The address is offseted to an aligned address where a raw copy would start. // If the clone copy is decomposed into load-stores - the address is adjusted to // point at where the array starts. @@ -566,6 +573,8 @@ if (!prepare_array_copy(phase, can_reshape, adr_src, base_src, adr_dest, base_dest, copy_type, value_type, disjoint_bases)) { + assert(adr_src == NULL, "no node can be left behind"); + assert(adr_dest == NULL, "no node can be left behind"); return NULL; } @@ -629,6 +638,10 @@ } if (!finish_transform(phase, can_reshape, ctl, mem)) { + if (can_reshape) { + // put in worklist, so that if it happens to be dead it is removed + phase->is_IterGVN()->_worklist.push(mem); + } return NULL; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/callGenerator.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/callGenerator.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/callGenerator.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/callGenerator.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -416,6 +416,13 @@ }; bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) { + // When inlining a virtual call, the null check at the call and the call itself can throw. These 2 paths have different + // expression stacks which causes late inlining to break. The MH invoker is not expected to be called from a method wih + // exception handlers. When there is no exception handler, GraphKit::builtin_throw() pops the stack which solves the issue + // of late inlining with exceptions. + assert(!jvms->method()->has_exception_handlers() || + (method()->intrinsic_id() != vmIntrinsics::_linkToVirtual && + method()->intrinsic_id() != vmIntrinsics::_linkToInterface), "no exception handler expected"); // Even if inlining is not allowed, a virtual call can be strength-reduced to a direct call. bool allow_inline = C->inlining_incrementally(); bool input_not_const = true; @@ -519,12 +526,20 @@ Node* receiver = jvms->map()->argument(jvms, 0); const Type* recv_type = C->initial_gvn()->type(receiver); if (recv_type->maybe_null()) { + if (C->print_inlining() || C->print_intrinsics()) { + C->print_inlining(method(), jvms->depth()-1, call_node()->jvms()->bci(), + "late call devirtualization failed (receiver may be null)"); + } return false; } // Even if inlining is not allowed, a virtual call can be strength-reduced to a direct call. bool allow_inline = C->inlining_incrementally(); if (!allow_inline && _callee->holder()->is_interface()) { // Don't convert the interface call to a direct call guarded by an interface subtype check. + if (C->print_inlining() || C->print_intrinsics()) { + C->print_inlining(method(), jvms->depth()-1, call_node()->jvms()->bci(), + "late call devirtualization failed (interface call)"); + } return false; } CallGenerator* cg = C->call_generator(_callee, diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/callnode.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/callnode.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/callnode.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/callnode.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1654,6 +1654,7 @@ init_req( KlassNode , klass_node); init_req( InitialTest , initial_test); init_req( ALength , topnode); + init_req( ValidLengthTest , topnode); C->add_macro_node(this); } @@ -1686,54 +1687,6 @@ return mark_node; } -//============================================================================= -Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if (remove_dead_region(phase, can_reshape)) return this; - // Don't bother trying to transform a dead node - if (in(0) && in(0)->is_top()) return NULL; - - const Type* type = phase->type(Ideal_length()); - if (type->isa_int() && type->is_int()->_hi < 0) { - if (can_reshape) { - PhaseIterGVN *igvn = phase->is_IterGVN(); - // Unreachable fall through path (negative array length), - // the allocation can only throw so disconnect it. - Node* proj = proj_out_or_null(TypeFunc::Control); - Node* catchproj = NULL; - if (proj != NULL) { - for (DUIterator_Fast imax, i = proj->fast_outs(imax); i < imax; i++) { - Node *cn = proj->fast_out(i); - if (cn->is_Catch()) { - catchproj = cn->as_Multi()->proj_out_or_null(CatchProjNode::fall_through_index); - break; - } - } - } - if (catchproj != NULL && catchproj->outcnt() > 0 && - (catchproj->outcnt() > 1 || - catchproj->unique_out()->Opcode() != Op_Halt)) { - assert(catchproj->is_CatchProj(), "must be a CatchProjNode"); - Node* nproj = catchproj->clone(); - igvn->register_new_node_with_optimizer(nproj); - - Node *frame = new ParmNode( phase->C->start(), TypeFunc::FramePtr ); - frame = phase->transform(frame); - // Halt & Catch Fire - Node* halt = new HaltNode(nproj, frame, "unexpected negative array length"); - phase->C->root()->add_req(halt); - phase->transform(halt); - - igvn->replace_node(catchproj, phase->C->top()); - return this; - } - } else { - // Can't correct it during regular GVN so register for IGVN - phase->C->record_for_igvn(this); - } - } - return NULL; -} - // Retrieve the length from the AllocateArrayNode. Narrow the type with a // CastII, if appropriate. If we are not allowed to create new nodes, and // a CastII is appropriate, return NULL. diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/callnode.hpp openjdk-17-17.0.4+8/src/hotspot/share/opto/callnode.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/callnode.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/callnode.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -913,6 +913,7 @@ KlassNode, // type (maybe dynamic) of the obj. InitialTest, // slow-path test (may be constant) ALength, // array length (or TOP if none) + ValidLengthTest, ParmLimit }; @@ -922,6 +923,7 @@ fields[KlassNode] = TypeInstPtr::NOTNULL; fields[InitialTest] = TypeInt::BOOL; fields[ALength] = t; // length (can be a bad length) + fields[ValidLengthTest] = TypeInt::BOOL; const TypeTuple *domain = TypeTuple::make(ParmLimit, fields); @@ -1016,18 +1018,16 @@ // class AllocateArrayNode : public AllocateNode { public: - AllocateArrayNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio, - Node* size, Node* klass_node, Node* initial_test, - Node* count_val - ) + AllocateArrayNode(Compile* C, const TypeFunc* atype, Node* ctrl, Node* mem, Node* abio, Node* size, Node* klass_node, + Node* initial_test, Node* count_val, Node* valid_length_test) : AllocateNode(C, atype, ctrl, mem, abio, size, klass_node, initial_test) { init_class_id(Class_AllocateArray); set_req(AllocateNode::ALength, count_val); + set_req(AllocateNode::ValidLengthTest, valid_length_test); } virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); // Dig the length operand out of a array allocation site. Node* Ideal_length() { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/cfgnode.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/cfgnode.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/cfgnode.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/cfgnode.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -2631,6 +2631,17 @@ // Rethrows always throw exceptions, never return if (call->entry_point() == OptoRuntime::rethrow_stub()) { f[CatchProjNode::fall_through_index] = Type::TOP; + } else if (call->is_AllocateArray()) { + Node* klass_node = call->in(AllocateNode::KlassNode); + Node* length = call->in(AllocateNode::ALength); + const Type* length_type = phase->type(length); + const Type* klass_type = phase->type(klass_node); + Node* valid_length_test = call->in(AllocateNode::ValidLengthTest); + const Type* valid_length_test_t = phase->type(valid_length_test); + if (length_type == Type::TOP || klass_type == Type::TOP || valid_length_test_t == Type::TOP || + valid_length_test_t->is_int()->is_con(0)) { + f[CatchProjNode::fall_through_index] = Type::TOP; + } } else if( call->req() > TypeFunc::Parms ) { const Type *arg0 = phase->type( call->in(TypeFunc::Parms) ); // Check for null receiver to virtual or interface calls diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/compile.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/compile.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/compile.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/compile.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -3740,7 +3740,7 @@ // 'fall-thru' path, so expected kids is 1 less. if (n->is_PCTable() && n->in(0) && n->in(0)->in(0)) { if (n->in(0)->in(0)->is_Call()) { - CallNode *call = n->in(0)->in(0)->as_Call(); + CallNode* call = n->in(0)->in(0)->as_Call(); if (call->entry_point() == OptoRuntime::rethrow_stub()) { required_outcnt--; // Rethrow always has 1 less kid } else if (call->req() > TypeFunc::Parms && @@ -3749,22 +3749,25 @@ // detected that the virtual call will always result in a null // pointer exception. The fall-through projection of this CatchNode // will not be populated. - Node *arg0 = call->in(TypeFunc::Parms); + Node* arg0 = call->in(TypeFunc::Parms); if (arg0->is_Type() && arg0->as_Type()->type()->higher_equal(TypePtr::NULL_PTR)) { required_outcnt--; } - } else if (call->entry_point() == OptoRuntime::new_array_Java() && - call->req() > TypeFunc::Parms+1 && - call->is_CallStaticJava()) { - // Check for negative array length. In such case, the optimizer has + } else if (call->entry_point() == OptoRuntime::new_array_Java() || + call->entry_point() == OptoRuntime::new_array_nozero_Java()) { + // Check for illegal array length. In such case, the optimizer has // detected that the allocation attempt will always result in an // exception. There is no fall-through projection of this CatchNode . - Node *arg1 = call->in(TypeFunc::Parms+1); - if (arg1->is_Type() && - arg1->as_Type()->type()->join(TypeInt::POS)->empty()) { + assert(call->is_CallStaticJava(), "static call expected"); + assert(call->req() == call->jvms()->endoff() + 1, "missing extra input"); + Node* valid_length_test = call->in(call->req()-1); + call->del_req(call->req()-1); + if (valid_length_test->find_int_con(1) == 0) { required_outcnt--; } + assert(n->outcnt() == required_outcnt, "malformed control flow"); + continue; } } } @@ -3773,6 +3776,14 @@ record_method_not_compilable("malformed control flow"); return true; // Not all targets reachable! } + } else if (n->is_PCTable() && n->in(0) && n->in(0)->in(0) && n->in(0)->in(0)->is_Call()) { + CallNode* call = n->in(0)->in(0)->as_Call(); + if (call->entry_point() == OptoRuntime::new_array_Java() || + call->entry_point() == OptoRuntime::new_array_nozero_Java()) { + assert(call->is_CallStaticJava(), "static call expected"); + assert(call->req() == call->jvms()->endoff() + 1, "missing extra input"); + call->del_req(call->req()-1); // valid length test useless now + } } // Check that I actually visited all kids. Unreached kids // must be infinite loops. diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/doCall.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/doCall.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/doCall.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/doCall.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,13 +67,17 @@ JVMState* jvms, bool allow_inline, float prof_factor, ciKlass* speculative_receiver_type, bool allow_intrinsics) { - ciMethod* caller = jvms->method(); - int bci = jvms->bci(); - Bytecodes::Code bytecode = caller->java_code_at_bci(bci); - guarantee(callee != NULL, "failed method resolution"); + assert(callee != NULL, "failed method resolution"); + + ciMethod* caller = jvms->method(); + int bci = jvms->bci(); + Bytecodes::Code bytecode = caller->java_code_at_bci(bci); + ciMethod* orig_callee = caller->get_method_at_bci(bci); const bool is_virtual_or_interface = (bytecode == Bytecodes::_invokevirtual) || - (bytecode == Bytecodes::_invokeinterface); + (bytecode == Bytecodes::_invokeinterface) || + (orig_callee->intrinsic_id() == vmIntrinsics::_linkToVirtual) || + (orig_callee->intrinsic_id() == vmIntrinsics::_linkToInterface); // Dtrace currently doesn't work unless all calls are vanilla if (env()->dtrace_method_probes()) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/escape.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/escape.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/escape.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/escape.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -618,6 +618,24 @@ add_java_object(n, PointsToNode::ArgEscape); break; } + case Op_Blackhole: { + // All blackhole pointer arguments are globally escaping. + // Only do this if there is at least one pointer argument. + // Do not add edges during first iteration because some could be + // not defined yet, defer to final step. + for (uint i = 0; i < n->req(); i++) { + Node* in = n->in(i); + if (in != nullptr) { + const Type* at = _igvn->type(in); + if (!at->isa_ptr()) continue; + + add_local_var(n, PointsToNode::GlobalEscape); + delayed_worklist->push(n); + break; + } + } + break; + } default: ; // Do nothing for nodes not related to EA. } @@ -787,6 +805,26 @@ add_edge(n_ptn, ptn); } } + break; + } + case Op_Blackhole: { + // All blackhole pointer arguments are globally escaping. + for (uint i = 0; i < n->req(); i++) { + Node* in = n->in(i); + if (in != nullptr) { + const Type* at = _igvn->type(in); + if (!at->isa_ptr()) continue; + + if (in->is_AddP()) { + in = get_addp_base(in); + } + + PointsToNode* ptn = ptnode_adr(in->_idx); + assert(ptn != nullptr, "should be defined already"); + set_escape_state(ptn, PointsToNode::GlobalEscape); + add_edge(n_ptn, ptn); + } + } break; } default: { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/graphKit.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/graphKit.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/graphKit.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/graphKit.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -615,6 +615,13 @@ const TypeOopPtr* val_type = TypeOopPtr::make_from_klass(env()->String_klass()); Node *store = access_store_at(ex_node, adr, adr_typ, null(), val_type, T_OBJECT, IN_HEAP); + if (!method()->has_exception_handlers()) { + // We don't need to preserve the stack if there's no handler as the entire frame is going to be popped anyway. + // This prevents issues with exception handling and late inlining. + set_sp(0); + clean_stack(0); + } + add_exception_state(make_exception_state(ex_node)); return; } @@ -2737,7 +2744,9 @@ // Make a catch node with just two handlers: fall-through and catch-all Node* i_o = _gvn.transform( new ProjNode(call, TypeFunc::I_O, separate_io_proj) ); Node* catc = _gvn.transform( new CatchNode(control(), i_o, 2) ); - Node* norm = _gvn.transform( new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci) ); + Node* norm = new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci); + _gvn.set_type_bottom(norm); + C->record_for_igvn(norm); Node* excp = _gvn.transform( new CatchProjNode(catc, CatchProjNode::catch_all_index, CatchProjNode::no_handler_bci) ); { PreserveJVMState pjvms(this); @@ -3976,20 +3985,28 @@ initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn); } + const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type(); + Node* valid_length_test = _gvn.intcon(1); + if (ary_type->klass()->is_array_klass()) { + BasicType bt = ary_type->klass()->as_array_klass()->element_type()->basic_type(); + jint max = TypeAryPtr::max_array_length(bt); + Node* valid_length_cmp = _gvn.transform(new CmpUNode(length, intcon(max))); + valid_length_test = _gvn.transform(new BoolNode(valid_length_cmp, BoolTest::le)); + } + // Create the AllocateArrayNode and its result projections AllocateArrayNode* alloc = new AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT), control(), mem, i_o(), size, klass_node, initial_slow_test, - length); + length, valid_length_test); // Cast to correct type. Note that the klass_node may be constant or not, // and in the latter case the actual array type will be inexact also. // (This happens via a non-constant argument to inline_native_newArray.) // In any case, the value of klass_node provides the desired array type. const TypeInt* length_type = _gvn.find_int_type(length); - const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type(); if (ary_type->isa_aryptr() && length_type != NULL) { // Try to get a better type than POS for the size ary_type = ary_type->is_aryptr()->cast_to_size(length_type); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/ifnode.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/ifnode.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/ifnode.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/ifnode.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1721,6 +1721,16 @@ // will cause this node to be reprocessed once the dead branch is killed. in(0)->outcnt() == 1))) { // IfNode control + if (in(0)->is_BaseCountedLoopEnd()) { + // CountedLoopEndNode may be eliminated by if subsuming, replace CountedLoopNode with LoopNode to + // avoid mismatching between CountedLoopNode and CountedLoopEndNode in the following optimization. + Node* head = unique_ctrl_out(); + if (head != NULL && head->is_BaseCountedLoop() && head->in(LoopNode::LoopBackControl) == this) { + Node* new_head = new LoopNode(head->in(LoopNode::EntryControl), this); + phase->is_IterGVN()->register_new_node_with_optimizer(new_head); + phase->is_IterGVN()->replace_node(head, new_head); + } + } return in(0)->in(0); } // no progress diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/library_call.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/library_call.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/library_call.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/library_call.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1073,7 +1073,6 @@ result = _gvn.transform(result); set_result(result); replace_in_map(index, result); - clear_upper_avx(); return true; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/loopnode.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/loopnode.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/loopnode.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/loopnode.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -683,8 +683,7 @@ Node* mem = safepoint->in(TypeFunc::Memory); - // We can only use that safepoint if there's not side effect - // between the backedge and the safepoint. + // We can only use that safepoint if there's no side effect between the backedge and the safepoint. // mm is used for book keeping MergeMemNode* mm = NULL; @@ -1241,16 +1240,6 @@ return false; } - if (x->in(LoopNode::LoopBackControl)->Opcode() == Op_SafePoint && - ((iv_bt == T_INT && LoopStripMiningIter != 0) || - iv_bt == T_LONG)) { - // Leaving the safepoint on the backedge and creating a - // CountedLoop will confuse optimizations. We can't move the - // safepoint around because its jvm state wouldn't match a new - // location. Give up on that loop. - return false; - } - Node* iftrue = back_control; uint iftrue_op = iftrue->Opcode(); Node* iff = iftrue->in(0); @@ -1479,6 +1468,37 @@ } } + Node* sfpt = NULL; + if (loop->_child == NULL) { + sfpt = find_safepoint(back_control, x, loop); + } else { + sfpt = iff->in(0); + if (sfpt->Opcode() != Op_SafePoint) { + sfpt = NULL; + } + } + + if (x->in(LoopNode::LoopBackControl)->Opcode() == Op_SafePoint) { + Node* backedge_sfpt = x->in(LoopNode::LoopBackControl); + if (((iv_bt == T_INT && LoopStripMiningIter != 0) || + iv_bt == T_LONG) && + sfpt == NULL) { + // Leaving the safepoint on the backedge and creating a + // CountedLoop will confuse optimizations. We can't move the + // safepoint around because its jvm state wouldn't match a new + // location. Give up on that loop. + return false; + } + if (is_deleteable_safept(backedge_sfpt)) { + lazy_replace(backedge_sfpt, iftrue); + if (loop->_safepts != NULL) { + loop->_safepts->yank(backedge_sfpt); + } + loop->_tail = iftrue; + } + } + + #ifdef ASSERT if (iv_bt == T_INT && !x->as_Loop()->is_transformed_long_inner_loop() && @@ -1517,18 +1537,6 @@ } set_subtree_ctrl(adjusted_limit, false); - if (iv_bt == T_INT && LoopStripMiningIter == 0) { - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt); - } - loop->_tail = iftrue; - } - } - // Build a canonical trip test. // Clone code, as old values may be in use. incr = incr->clone(); @@ -1600,13 +1608,11 @@ assert(iff->outcnt() == 0, "should be dead now"); lazy_replace( iff, le ); // fix 'get_ctrl' - Node *sfpt2 = le->in(0); - Node* entry_control = init_control; bool strip_mine_loop = iv_bt == T_INT && LoopStripMiningIter > 1 && loop->_child == NULL && - sfpt2->Opcode() == Op_SafePoint && + sfpt != NULL && !loop->_has_call; IdealLoopTree* outer_ilt = NULL; if (strip_mine_loop) { @@ -1632,30 +1638,30 @@ if (iv_bt == T_INT && (LoopStripMiningIter == 0 || strip_mine_loop)) { // Check for immediately preceding SafePoint and remove - if (sfpt2->Opcode() == Op_SafePoint && (LoopStripMiningIter != 0 || is_deleteable_safept(sfpt2))) { + if (sfpt != NULL && (LoopStripMiningIter != 0 || is_deleteable_safept(sfpt))) { if (strip_mine_loop) { Node* outer_le = outer_ilt->_tail->in(0); - Node* sfpt = sfpt2->clone(); - sfpt->set_req(0, iffalse); - outer_le->set_req(0, sfpt); + Node* sfpt_clone = sfpt->clone(); + sfpt_clone->set_req(0, iffalse); + outer_le->set_req(0, sfpt_clone); - Node* polladdr = sfpt->in(TypeFunc::Parms); + Node* polladdr = sfpt_clone->in(TypeFunc::Parms); if (polladdr != nullptr && polladdr->is_Load()) { // Polling load should be pinned outside inner loop. Node* new_polladdr = polladdr->clone(); new_polladdr->set_req(0, iffalse); _igvn.register_new_node_with_optimizer(new_polladdr, polladdr); set_ctrl(new_polladdr, iffalse); - sfpt->set_req(TypeFunc::Parms, new_polladdr); + sfpt_clone->set_req(TypeFunc::Parms, new_polladdr); } // When this code runs, loop bodies have not yet been populated. const bool body_populated = false; - register_control(sfpt, outer_ilt, iffalse, body_populated); - set_idom(outer_le, sfpt, dom_depth(sfpt)); + register_control(sfpt_clone, outer_ilt, iffalse, body_populated); + set_idom(outer_le, sfpt_clone, dom_depth(sfpt_clone)); } - lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); + lazy_replace(sfpt, sfpt->in(TypeFunc::Control)); if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt2); + loop->_safepts->yank(sfpt); } } } @@ -3288,7 +3294,7 @@ if (_head->is_CountedLoop() || phase->is_counted_loop(_head, loop, T_INT)) { - if (LoopStripMiningIter == 0 || (LoopStripMiningIter > 1 && _child == NULL)) { + if (LoopStripMiningIter == 0 || _head->as_CountedLoop()->is_strip_mined()) { // Indicate we do not need a safepoint here _has_sfpt = 1; } @@ -3714,11 +3720,11 @@ //----------------------------build_and_optimize------------------------------- // Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to // its corresponding LoopNode. If 'optimize' is true, do some loop cleanups. -void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) { +void PhaseIdealLoop::build_and_optimize() { assert(!C->post_loop_opts_phase(), "no loop opts allowed"); - bool do_split_ifs = (mode == LoopOptsDefault); - bool skip_loop_opts = (mode == LoopOptsNone); + bool do_split_ifs = (_mode == LoopOptsDefault); + bool skip_loop_opts = (_mode == LoopOptsNone); int old_progress = C->major_progress(); uint orig_worklist_size = _igvn._worklist.size(); @@ -3789,9 +3795,9 @@ BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); // Nothing to do, so get out bool stop_early = !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only && - !bs->is_gc_specific_loop_opts_pass(mode); + !bs->is_gc_specific_loop_opts_pass(_mode); bool do_expensive_nodes = C->should_optimize_expensive_nodes(_igvn); - bool strip_mined_loops_expanded = bs->strip_mined_loops_expanded(mode); + bool strip_mined_loops_expanded = bs->strip_mined_loops_expanded(_mode); if (stop_early && !do_expensive_nodes) { return; } @@ -3883,7 +3889,7 @@ if (_verify_only) { C->restore_major_progress(old_progress); - assert(C->unique() == unique, "verification mode made Nodes? ? ?"); + assert(C->unique() == unique, "verification _mode made Nodes? ? ?"); assert(_igvn._worklist.size() == orig_worklist_size, "shouldn't push anything"); return; } @@ -3913,8 +3919,8 @@ #ifndef PRODUCT C->verify_graph_edges(); if (_verify_me) { // Nested verify pass? - // Check to see if the verify mode is broken - assert(C->unique() == unique, "non-optimize mode made Nodes? ? ?"); + // Check to see if the verify _mode is broken + assert(C->unique() == unique, "non-optimize _mode made Nodes? ? ?"); return; } if (VerifyLoopOptimizations) verify(); @@ -3928,7 +3934,7 @@ return; } - if (mode == LoopOptsMaxUnroll) { + if (_mode == LoopOptsMaxUnroll) { for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { IdealLoopTree* lpt = iter.current(); if (lpt->is_innermost() && lpt->_allow_optimizations && !lpt->_has_call && lpt->is_counted()) { @@ -3949,7 +3955,7 @@ return; } - if (bs->optimize_loops(this, mode, visited, nstack, worklist)) { + if (bs->optimize_loops(this, _mode, visited, nstack, worklist)) { return; } @@ -4090,7 +4096,14 @@ sw.transform_loop(lpt, true); } } else if (cl->is_main_loop()) { - sw.transform_loop(lpt, true); + if (!sw.transform_loop(lpt, true)) { + // Instigate more unrolling for optimization when vectorization fails. + if (cl->has_passed_slp()) { + C->set_major_progress(); + cl->set_notpassed_slp(); + cl->mark_do_unroll_only(); + } + } } } } @@ -5353,38 +5366,45 @@ } assert(early == legal || legal != C->root(), "bad dominance of inputs"); + if (least != early) { + // Move the node above predicates as far up as possible so a + // following pass of loop predication doesn't hoist a predicate + // that depends on it above that node. + Node* new_ctrl = least; + for (;;) { + if (!new_ctrl->is_Proj()) { + break; + } + CallStaticJavaNode* call = new_ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + if (call == NULL) { + break; + } + int req = call->uncommon_trap_request(); + Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); + if (trap_reason != Deoptimization::Reason_loop_limit_check && + trap_reason != Deoptimization::Reason_predicate && + trap_reason != Deoptimization::Reason_profile_predicate) { + break; + } + Node* c = new_ctrl->in(0)->in(0); + if (is_dominator(c, early) && c != early) { + break; + } + new_ctrl = c; + } + least = new_ctrl; + } // Try not to place code on a loop entry projection // which can inhibit range check elimination. - if (least != early) { + if (least != early && !BarrierSet::barrier_set()->barrier_set_c2()->is_gc_specific_loop_opts_pass(_mode)) { Node* ctrl_out = least->unique_ctrl_out(); if (ctrl_out && ctrl_out->is_Loop() && - least == ctrl_out->in(LoopNode::EntryControl)) { - // Move the node above predicates as far up as possible so a - // following pass of loop predication doesn't hoist a predicate - // that depends on it above that node. - Node* new_ctrl = least; - for (;;) { - if (!new_ctrl->is_Proj()) { - break; - } - CallStaticJavaNode* call = new_ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); - if (call == NULL) { - break; - } - int req = call->uncommon_trap_request(); - Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); - if (trap_reason != Deoptimization::Reason_loop_limit_check && - trap_reason != Deoptimization::Reason_predicate && - trap_reason != Deoptimization::Reason_profile_predicate) { - break; - } - Node* c = new_ctrl->in(0)->in(0); - if (is_dominator(c, early) && c != early) { - break; - } - new_ctrl = c; + least == ctrl_out->in(LoopNode::EntryControl) && + (ctrl_out->is_CountedLoop() || ctrl_out->is_OuterStripMinedLoop())) { + Node* least_dom = idom(least); + if (get_loop(least_dom)->is_member(get_loop(least))) { + least = least_dom; } - least = new_ctrl; } } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/loopnode.hpp openjdk-17-17.0.4+8/src/hotspot/share/opto/loopnode.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/loopnode.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/loopnode.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1050,9 +1050,10 @@ Node **_idom; // Array of immediate dominators uint *_dom_depth; // Used for fast LCA test GrowableArray* _dom_stk; // For recomputation of dom depth + LoopOptsMode _mode; // build the loop tree and perform any requested optimizations - void build_and_optimize(LoopOptsMode mode); + void build_and_optimize(); // Dominators for the sea of nodes void Dominators(); @@ -1063,9 +1064,10 @@ _igvn(igvn), _verify_me(nullptr), _verify_only(false), + _mode(mode), _nodes_required(UINT_MAX) { assert(mode != LoopOptsVerify, "wrong constructor to verify IdealLoop"); - build_and_optimize(mode); + build_and_optimize(); } #ifndef PRODUCT @@ -1076,8 +1078,9 @@ _igvn(igvn), _verify_me(verify_me), _verify_only(verify_me == nullptr), + _mode(LoopOptsVerify), _nodes_required(UINT_MAX) { - build_and_optimize(LoopOptsVerify); + build_and_optimize(); } #endif diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/loopopts.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/loopopts.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/loopopts.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/loopopts.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -3728,6 +3728,8 @@ set_ctrl(neg_stride, C->root()); Node *post = new AddINode(opaq, neg_stride); register_new_node(post, c); + post = new CastIINode(post, phi->bottom_type()); // preserve the iv phi's type + register_new_node(post, c); _igvn.rehash_node_delayed(use); for (uint j = 1; j < use->req(); j++) { if (use->in(j) == phi) diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/loopPredicate.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/loopPredicate.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/loopPredicate.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/loopPredicate.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1012,13 +1012,15 @@ GrowableArray _freqs; // cache frequencies PhaseIdealLoop* _phase; - void set_rounding(int mode) { - // fesetround is broken on windows - NOT_WINDOWS(fesetround(mode);) - } - - void check_frequency(float f) { - NOT_WINDOWS(assert(f <= 1 && f >= 0, "Incorrect frequency");) + float check_and_truncate_frequency(float f) { + assert(f >= 0, "Incorrect frequency"); + // We do not perform an exact (f <= 1) check + // this would be error prone with rounding of floats. + // Performing a check like (f <= 1+eps) would be of benefit, + // however, it is not evident how to determine such an eps, + // given that an arbitrary number of add/mul operations + // are performed on these frequencies. + return (f > 1) ? 1 : f; } public: @@ -1028,7 +1030,6 @@ float to(Node* n) { // post order walk on the CFG graph from n to _dom - set_rounding(FE_TOWARDZERO); // make sure rounding doesn't push frequency above 1 IdealLoopTree* loop = _phase->get_loop(_dom); Node* c = n; for (;;) { @@ -1055,14 +1056,12 @@ inner_head = inner_loop->_head->as_Loop(); inner_head->verify_strip_mined(1); } - set_rounding(FE_UPWARD); // make sure rounding doesn't push frequency above 1 float loop_exit_cnt = 0.0f; for (uint i = 0; i < inner_loop->_body.size(); i++) { Node *n = inner_loop->_body[i]; float c = inner_loop->compute_profile_trip_cnt_helper(n); loop_exit_cnt += c; } - set_rounding(FE_TOWARDZERO); float cnt = -1; if (n->in(0)->is_If()) { IfNode* iff = n->in(0)->as_If(); @@ -1082,9 +1081,9 @@ cnt = p * jmp->_fcnt; } float this_exit_f = cnt > 0 ? cnt / loop_exit_cnt : 0; - check_frequency(this_exit_f); + this_exit_f = check_and_truncate_frequency(this_exit_f); f = f * this_exit_f; - check_frequency(f); + f = check_and_truncate_frequency(f); } else { float p = -1; if (n->in(0)->is_If()) { @@ -1097,7 +1096,7 @@ p = n->in(0)->as_Jump()->_probs[n->as_JumpProj()->_con]; } f = f * p; - check_frequency(f); + f = check_and_truncate_frequency(f); } _freqs.at_put_grow(n->_idx, (float)f, -1); _stack.pop(); @@ -1105,7 +1104,7 @@ float prev_f = _freqs_stack.pop(); float new_f = f; f = new_f + prev_f; - check_frequency(f); + f = check_and_truncate_frequency(f); uint i = _stack.index(); if (i < n->req()) { c = n->in(i); @@ -1118,9 +1117,7 @@ } } if (_stack.size() == 0) { - set_rounding(FE_TONEAREST); - check_frequency(f); - return f; + return check_and_truncate_frequency(f); } } else if (c->is_Loop()) { ShouldNotReachHere(); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/loopTransform.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/loopTransform.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/loopTransform.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/loopTransform.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1197,7 +1197,7 @@ } Node* PhaseIdealLoop::cast_incr_before_loop(Node* incr, Node* ctrl, Node* loop) { - Node* castii = new CastIINode(incr, TypeInt::INT, ConstraintCastNode::StrongDependency); + Node* castii = new CastIINode(incr, TypeInt::INT, ConstraintCastNode::UnconditionalDependency); castii->set_req(0, ctrl); register_new_node(castii, ctrl); for (DUIterator_Fast imax, i = incr->fast_outs(imax); i < imax; i++) { @@ -1910,6 +1910,12 @@ } void PhaseIdealLoop::update_main_loop_skeleton_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, int stride_con) { + if (init->Opcode() == Op_CastII) { + // skip over the cast added by PhaseIdealLoop::cast_incr_before_loop() when pre/post/main loops are created because + // it can get in the way of type propagation + assert(((CastIINode*)init)->carry_dependency() && loop_head->skip_predicates() == init->in(0), "casted iv phi from pre loop expected"); + init = init->in(1); + } // Search for skeleton predicates and update them according to the new stride Node* entry = ctrl; Node* prev_proj = ctrl; @@ -3370,6 +3376,11 @@ //============================================================================= //------------------------------iteration_split_impl--------------------------- bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_new) { + if (!_head->is_Loop()) { + // Head could be a region with a NeverBranch that was added in beautify loops but the region was not + // yet transformed into a LoopNode. Bail out and wait until beautify loops turns it into a Loop node. + return false; + } // Compute loop trip count if possible. compute_trip_count(phase); @@ -3849,10 +3860,17 @@ index = new LShiftXNode(index, shift->in(2)); _igvn.register_new_node_with_optimizer(index); } - index = new AddPNode(base, base, index); - _igvn.register_new_node_with_optimizer(index); - Node* from = new AddPNode(base, index, offset); + Node* from = new AddPNode(base, base, index); _igvn.register_new_node_with_optimizer(from); + // For normal array fills, C2 uses two AddP nodes for array element + // addressing. But for array fills with Unsafe call, there's only one + // AddP node adding an absolute offset, so we do a NULL check here. + assert(offset != NULL || C->has_unsafe_access(), + "Only array fills with unsafe have no extra offset"); + if (offset != NULL) { + from = new AddPNode(base, from, offset); + _igvn.register_new_node_with_optimizer(from); + } // Compute the number of elements to copy Node* len = new SubINode(head->limit(), head->init_trip()); _igvn.register_new_node_with_optimizer(len); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/macro.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/macro.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/macro.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/macro.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1208,7 +1208,8 @@ AllocateNode* alloc, // allocation node to be expanded Node* length, // array length for an array allocation const TypeFunc* slow_call_type, // Type of slow call - address slow_call_address // Address of slow call + address slow_call_address, // Address of slow call + Node* valid_length_test // whether length is valid or not ) { Node* ctrl = alloc->in(TypeFunc::Control); @@ -1394,6 +1395,12 @@ // Copy debug information and adjust JVMState information, then replace // allocate node with the call call->copy_call_debug_info(&_igvn, alloc); + // For array allocations, copy the valid length check to the call node so Compile::final_graph_reshaping() can verify + // that the call has the expected number of CatchProj nodes (in case the allocation always fails and the fallthrough + // path dies). + if (valid_length_test != NULL) { + call->add_req(valid_length_test); + } if (expand_fast_path) { call->set_cnt(PROB_UNLIKELY_MAG(4)); // Same effect as RC_UNCOMMON. } else { @@ -1875,11 +1882,12 @@ void PhaseMacroExpand::expand_allocate(AllocateNode *alloc) { expand_allocate_common(alloc, NULL, OptoRuntime::new_instance_Type(), - OptoRuntime::new_instance_Java()); + OptoRuntime::new_instance_Java(), NULL); } void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) { Node* length = alloc->in(AllocateNode::ALength); + Node* valid_length_test = alloc->in(AllocateNode::ValidLengthTest); InitializeNode* init = alloc->initialization(); Node* klass_node = alloc->in(AllocateNode::KlassNode); ciKlass* k = _igvn.type(klass_node)->is_klassptr()->klass(); @@ -1894,7 +1902,7 @@ } expand_allocate_common(alloc, length, OptoRuntime::new_array_Type(), - slow_call_address); + slow_call_address, valid_length_test); } //-------------------mark_eliminated_box---------------------------------- diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/macro.hpp openjdk-17-17.0.4+8/src/hotspot/share/opto/macro.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/macro.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/macro.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -92,8 +92,8 @@ void expand_allocate_common(AllocateNode* alloc, Node* length, const TypeFunc* slow_call_type, - address slow_call_address); - void yank_initalize_node(InitializeNode* node); + address slow_call_address, + Node* valid_length_test); void yank_alloc_node(AllocateNode* alloc); Node *value_from_mem(Node *mem, Node *ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc); Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc, Node_Stack *value_phis, int level); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/movenode.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/movenode.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/movenode.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/movenode.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -75,21 +75,25 @@ // Return a node which is more "ideal" than the current node. // Move constants to the right. Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(0) && remove_dead_region(phase, can_reshape) ) return this; + if (in(0) != NULL && remove_dead_region(phase, can_reshape)) { + return this; + } // Don't bother trying to transform a dead node - if( in(0) && in(0)->is_top() ) return NULL; + if (in(0) != NULL && in(0)->is_top()) { + return NULL; + } assert(in(Condition) != this && - in(IfFalse) != this && - in(IfTrue) != this, "dead loop in CMoveNode::Ideal" ); - if( phase->type(in(Condition)) == Type::TOP ) - return NULL; // return NULL when Condition is dead - - if( in(IfFalse)->is_Con() && !in(IfTrue)->is_Con() ) { - if( in(Condition)->is_Bool() ) { - BoolNode* b = in(Condition)->as_Bool(); - BoolNode* b2 = b->negate(phase); - return make(in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type); - } + in(IfFalse) != this && + in(IfTrue) != this, "dead loop in CMoveNode::Ideal"); + if (phase->type(in(Condition)) == Type::TOP || + phase->type(in(IfFalse)) == Type::TOP || + phase->type(in(IfTrue)) == Type::TOP) { + return NULL; + } + // Canonicalize the node by moving constants to the right input. + if (in(Condition)->is_Bool() && phase->type(in(IfFalse))->singleton() && !phase->type(in(IfTrue))->singleton()) { + BoolNode* b = in(Condition)->as_Bool()->negate(phase); + return make(in(Control), phase->transform(b), in(IfTrue), in(IfFalse), _type); } return NULL; } @@ -191,14 +195,10 @@ // If zero is on the left (false-case, no-move-case) it must mean another // constant is on the right (otherwise the shared CMove::Ideal code would - // have moved the constant to the right). This situation is bad for Intel - // and a don't-care for Sparc. It's bad for Intel because the zero has to - // be manifested in a register with a XOR which kills flags, which are live - // on input to the CMoveI, leading to a situation which causes excessive - // spilling on Intel. For Sparc, if the zero in on the left the Sparc will - // zero a register via G0 and conditionally-move the other constant. If the - // zero is on the right, the Sparc will load the first constant with a - // 13-bit set-lo and conditionally move G0. See bug 4677505. + // have moved the constant to the right). This situation is bad for x86 because + // the zero has to be manifested in a register with a XOR which kills flags, + // which are live on input to the CMoveI, leading to a situation which causes + // excessive spilling. See bug 4677505. if( phase->type(in(IfFalse)) == TypeInt::ZERO && !(phase->type(in(IfTrue)) == TypeInt::ZERO) ) { if( in(Condition)->is_Bool() ) { BoolNode* b = in(Condition)->as_Bool(); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/parse2.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/parse2.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/parse2.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/parse2.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1876,33 +1876,35 @@ case Bytecodes::_bipush: push(intcon(iter().get_constant_u1())); break; case Bytecodes::_sipush: push(intcon(iter().get_constant_u2())); break; case Bytecodes::_aconst_null: push(null()); break; + case Bytecodes::_ldc: case Bytecodes::_ldc_w: - case Bytecodes::_ldc2_w: - // If the constant is unresolved, run this BC once in the interpreter. - { - ciConstant constant = iter().get_constant(); - if (!constant.is_valid() || - (constant.basic_type() == T_OBJECT && - !constant.as_object()->is_loaded())) { - int index = iter().get_constant_pool_index(); - constantTag tag = iter().get_constant_pool_tag(index); - uncommon_trap(Deoptimization::make_trap_request - (Deoptimization::Reason_unloaded, - Deoptimization::Action_reinterpret, - index), - NULL, tag.internal_name()); - break; - } + case Bytecodes::_ldc2_w: { + ciConstant constant = iter().get_constant(); + if (constant.is_loaded()) { assert(constant.basic_type() != T_OBJECT || constant.as_object()->is_instance(), "must be java_mirror of klass"); const Type* con_type = Type::make_from_constant(constant); if (con_type != NULL) { push_node(con_type->basic_type(), makecon(con_type)); } - } + } else { + // If the constant is unresolved or in error state, run this BC in the interpreter. + if (iter().is_in_error()) { + uncommon_trap(Deoptimization::make_trap_request(Deoptimization::Reason_unhandled, + Deoptimization::Action_none), + NULL, "constant in error state", true /* must_throw */); + } else { + int index = iter().get_constant_pool_index(); + uncommon_trap(Deoptimization::make_trap_request(Deoptimization::Reason_unloaded, + Deoptimization::Action_reinterpret, + index), + NULL, "unresolved constant", false /* must_throw */); + } + } break; + } case Bytecodes::_aload_0: push( local(0) ); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/phaseX.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/phaseX.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/phaseX.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/phaseX.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1510,13 +1510,13 @@ // Return counted loop Phi if as a counted loop exit condition, cmp // compares the the induction variable with n -static PhiNode* countedloop_phi_from_cmp(CmpINode* cmp, Node* n) { +static PhiNode* countedloop_phi_from_cmp(CmpNode* cmp, Node* n) { for (DUIterator_Fast imax, i = cmp->fast_outs(imax); i < imax; i++) { Node* bol = cmp->fast_out(i); for (DUIterator_Fast i2max, i2 = bol->fast_outs(i2max); i2 < i2max; i2++) { Node* iff = bol->fast_out(i2); - if (iff->is_CountedLoopEnd()) { - CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); + if (iff->is_BaseCountedLoopEnd()) { + BaseCountedLoopEndNode* cle = iff->as_BaseCountedLoopEnd(); if (cle->limit() == n) { PhiNode* phi = cle->phi(); if (phi != NULL) { @@ -1693,7 +1693,7 @@ case Op_DivI: case Op_ModI: { // Type of divisor includes 0? - if (n->in(2)->is_top()) { + if (type(n->in(2)) == Type::TOP) { // 'n' is dead. Treat as if zero check is still there to avoid any further optimizations. return false; } @@ -1703,7 +1703,7 @@ case Op_DivL: case Op_ModL: { // Type of divisor includes 0? - if (n->in(2)->is_top()) { + if (type(n->in(2)) == Type::TOP) { // 'n' is dead. Treat as if zero check is still there to avoid any further optimizations. return false; } @@ -1834,8 +1834,8 @@ // If n is used in a counted loop exit condition then the type // of the counted loop's Phi depends on the type of n. See // PhiNode::Value(). - if (m_op == Op_CmpI) { - PhiNode* phi = countedloop_phi_from_cmp((CmpINode*)m, n); + if (m_op == Op_CmpI || m_op == Op_CmpL) { + PhiNode* phi = countedloop_phi_from_cmp(m->as_Cmp(), n); if (phi != NULL) { worklist.push(phi); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/split_if.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/split_if.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/split_if.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/split_if.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -128,8 +128,8 @@ } } else { // We might see an Opaque1 from a loop limit check here - assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1, "unexpected node type"); - Node *use_c = use->is_If() ? use->in(0) : get_ctrl(use); + assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1 || use->is_AllocateArray(), "unexpected node type"); + Node *use_c = (use->is_If() || use->is_AllocateArray()) ? use->in(0) : get_ctrl(use); if (use_c == blk1 || use_c == blk2) { assert(use->is_CMove(), "unexpected node type"); continue; @@ -166,14 +166,15 @@ --j; } else { // We might see an Opaque1 from a loop limit check here - assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1, "unexpected node type"); - assert(u->in(1) == bol, ""); + assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1 || u->is_AllocateArray(), "unexpected node type"); + assert(u->is_AllocateArray() || u->in(1) == bol, ""); + assert(!u->is_AllocateArray() || u->in(AllocateNode::ValidLengthTest) == bol, "wrong input to AllocateArray"); // Get control block of either the CMove or the If input - Node *u_ctrl = u->is_If() ? u->in(0) : get_ctrl(u); + Node *u_ctrl = (u->is_If() || u->is_AllocateArray()) ? u->in(0) : get_ctrl(u); assert((u_ctrl != blk1 && u_ctrl != blk2) || u->is_CMove(), "won't converge"); Node *x = bol->clone(); register_new_node(x, u_ctrl); - _igvn.replace_input_of(u, 1, x); + _igvn.replace_input_of(u, u->is_AllocateArray() ? AllocateNode::ValidLengthTest : 1, x); --j; } } @@ -200,6 +201,24 @@ return true; } } + if (n->Opcode() == Op_OpaqueLoopStride || n->Opcode() == Op_OpaqueLoopInit) { + Unique_Node_List wq; + wq.push(n); + for (uint i = 0; i < wq.size(); i++) { + Node* m = wq.at(i); + if (m->is_If()) { + assert(skeleton_predicate_has_opaque(m->as_If()), "opaque node not reachable from if?"); + Node* bol = clone_skeleton_predicate_bool(m, NULL, NULL, m->in(0)); + _igvn.replace_input_of(m, 1, bol); + } else { + assert(!m->is_CFG(), "not CFG expected"); + for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) { + Node* u = m->fast_out(j); + wq.push(u); + } + } + } + } // See if splitting-up a Store. Any anti-dep loads must go up as // well. An anti-dep load might be in the wrong block, because in diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/subtypenode.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/subtypenode.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/subtypenode.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/subtypenode.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -135,7 +135,7 @@ Node* obj = AddPNode::Ideal_base_and_offset(addr, phase, con); if (con == oopDesc::klass_offset_in_bytes() && obj != NULL) { assert(is_oop(phase, obj), "only for oop input"); - set_req(ObjOrSubKlass, obj); + set_req_X(ObjOrSubKlass, obj, phase); return this; } } @@ -144,7 +144,7 @@ Node* allocated_klass = AllocateNode::Ideal_klass(obj_or_subklass, phase); if (allocated_klass != NULL) { assert(is_oop(phase, obj_or_subklass), "only for oop input"); - set_req(ObjOrSubKlass, allocated_klass); + set_req_X(ObjOrSubKlass, allocated_klass, phase); return this; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/superword.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/superword.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/superword.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/superword.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -95,38 +95,48 @@ static const bool _do_vector_loop_experimental = false; // Experimental vectorization which uses data from loop unrolling. //------------------------------transform_loop--------------------------- -void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { +bool SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { assert(UseSuperWord, "should be"); // SuperWord only works with power of two vector sizes. int vector_width = Matcher::vector_width_in_bytes(T_BYTE); if (vector_width < 2 || !is_power_of_2(vector_width)) { - return; + return false; } assert(lpt->_head->is_CountedLoop(), "must be"); CountedLoopNode *cl = lpt->_head->as_CountedLoop(); - if (!cl->is_valid_counted_loop(T_INT)) return; // skip malformed counted loop + if (!cl->is_valid_counted_loop(T_INT)) { + return false; // skip malformed counted loop + } bool post_loop_allowed = (PostLoopMultiversioning && Matcher::has_predicated_vectors() && cl->is_post_loop()); if (post_loop_allowed) { - if (cl->is_reduction_loop()) return; // no predication mapping + if (cl->is_reduction_loop()) { + return false; // no predication mapping + } Node *limit = cl->limit(); - if (limit->is_Con()) return; // non constant limits only + if (limit->is_Con()) { + return false; // non constant limits only + } // Now check the limit for expressions we do not handle if (limit->is_Add()) { Node *in2 = limit->in(2); if (in2->is_Con()) { int val = in2->get_int(); // should not try to program these cases - if (val < 0) return; + if (val < 0) { + return false; + } } } } // skip any loop that has not been assigned max unroll by analysis if (do_optimization) { - if (SuperWordLoopUnrollAnalysis && cl->slp_max_unroll() == 0) return; + if (SuperWordLoopUnrollAnalysis && cl->slp_max_unroll() == 0) { + return false; + } } // Check for no control flow in body (other than exit) @@ -141,28 +151,32 @@ lpt->dump_head(); } #endif - return; + return false; } // Make sure the are no extra control users of the loop backedge if (cl->back_control()->outcnt() != 1) { - return; + return false; } // Skip any loops already optimized by slp - if (cl->is_vectorized_loop()) return; + if (cl->is_vectorized_loop()) { + return false; + } - if (cl->is_unroll_only()) return; + if (cl->is_unroll_only()) { + return false; + } if (cl->is_main_loop()) { // Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit)))) CountedLoopEndNode* pre_end = find_pre_loop_end(cl); if (pre_end == NULL) { - return; + return false; } Node* pre_opaq1 = pre_end->limit(); if (pre_opaq1->Opcode() != Op_Opaque1) { - return; + return false; } set_pre_loop_end(pre_end); } @@ -175,9 +189,10 @@ // For now, define one block which is the entire loop body set_bb(cl); + bool success = true; if (do_optimization) { assert(_packset.length() == 0, "packset must be empty"); - SLP_extract(); + success = SLP_extract(); if (PostLoopMultiversioning && Matcher::has_predicated_vectors()) { if (cl->is_vectorized_loop() && cl->is_main_loop() && !cl->is_reduction_loop()) { IdealLoopTree *lpt_next = lpt->_next; @@ -192,6 +207,7 @@ } } } + return success; } //------------------------------early unrolling analysis------------------------------ @@ -451,7 +467,7 @@ // inserting scalar promotion, vector creation from multiple scalars, and // extraction of scalar values from vectors. // -void SuperWord::SLP_extract() { +bool SuperWord::SLP_extract() { #ifndef PRODUCT if (_do_vector_loop && TraceSuperWord) { @@ -466,7 +482,7 @@ #endif // Ready the block if (!construct_bb()) { - return; // Exit if no interesting nodes or complex graph. + return false; // Exit if no interesting nodes or complex graph. } // build _dg, _disjoint_ptrs @@ -483,7 +499,7 @@ hoist_loads_in_graph(); // this only rebuild the graph; all basic structs need rebuild explicitly if (!construct_bb()) { - return; // Exit if no interesting nodes or complex graph. + return false; // Exit if no interesting nodes or complex graph. } dependence_graph(); compute_max_depth(); @@ -511,7 +527,7 @@ find_adjacent_refs(); if (align_to_ref() == NULL) { - return; // Did not find memory reference to align vectors + return false; // Did not find memory reference to align vectors } extend_packlist(); @@ -563,15 +579,15 @@ // map base types for vector usage compute_vector_element_type(); } else { - return; + return false; } } else { // for some reason we could not map the slp analysis state of the vectorized loop - return; + return false; } } - output(); + return output(); } //------------------------------find_adjacent_refs--------------------------- @@ -2385,17 +2401,11 @@ //------------------------------output--------------------------- // Convert packs into vector node operations -void SuperWord::output() { +bool SuperWord::output() { CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); Compile* C = _phase->C; if (_packset.length() == 0) { - if (cl->is_main_loop()) { - // Instigate more unrolling for optimization when vectorization fails. - C->set_major_progress(); - cl->set_notpassed_slp(); - cl->mark_do_unroll_only(); - } - return; + return false; } #ifndef PRODUCT @@ -2429,7 +2439,7 @@ if (do_reserve_copy() && !make_reversable.has_reserved()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: loop was not reserved correctly, exiting SuperWord");}) - return; + return false; } for (int i = 0; i < _block.length(); i++) { @@ -2474,7 +2484,7 @@ if (val == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: val should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2518,7 +2528,7 @@ if (in1 == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: in1 should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2527,7 +2537,7 @@ if (in2 == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: in2 should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2561,7 +2571,7 @@ } else if (is_cmov_pack(p)) { if (can_process_post_loop) { // do not refactor of flow in post loop context - return; + return false; } if (!n->is_CMove()) { continue; @@ -2578,7 +2588,7 @@ if (!bol->is_Bool()) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: expected %d bool node, exiting SuperWord", bol->_idx); bol->dump();}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2594,7 +2604,7 @@ if (src1 == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: src1 should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2602,7 +2612,7 @@ if (src2 == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: src2 should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2626,7 +2636,7 @@ } else { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: ShouldNotReachHere, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2635,7 +2645,7 @@ if (vn == NULL) { if (do_reserve_copy()){ NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: got NULL node, cannot proceed, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2653,7 +2663,7 @@ // first check if the vector size if the maximum vector which we can use on the machine, // other vector size have reduced values for predicated data mapping. if (vlen_in_bytes != (uint)MaxVectorSize) { - return; + return false; } } @@ -2726,7 +2736,7 @@ make_reversable.use_new(); } NOT_PRODUCT(if(is_trace_loop_reverse()) {tty->print_cr("\n Final loop after SuperWord"); print_loop(true);}) - return; + return true; } //------------------------------vector_opd--------------------------- diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/superword.hpp openjdk-17-17.0.4+8/src/hotspot/share/opto/superword.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/superword.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/superword.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -286,7 +286,7 @@ public: SuperWord(PhaseIdealLoop* phase); - void transform_loop(IdealLoopTree* lpt, bool do_optimization); + bool transform_loop(IdealLoopTree* lpt, bool do_optimization); void unrolling_analysis(int &local_loop_unroll_factor); @@ -422,7 +422,7 @@ // methods // Extract the superword level parallelism - void SLP_extract(); + bool SLP_extract(); // Find the adjacent memory references and create pack pairs for them. void find_adjacent_refs(); // Tracing support @@ -509,7 +509,7 @@ Node* find_last_mem_state(Node_List* pk, Node* first_mem); // Convert packs into vector node operations - void output(); + bool output(); // Create a vector operand for the nodes in pack p for operand: in(opd_idx) Node* vector_opd(Node_List* p, int opd_idx); // Can code be generated for pack p? diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/opto/vector.cpp openjdk-17-17.0.4+8/src/hotspot/share/opto/vector.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/opto/vector.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/opto/vector.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -315,6 +315,21 @@ } new_phi = C->initial_gvn()->transform(new_phi); return new_phi; + } else if (vbox->is_Phi() && (vect->is_Vector() || vect->is_LoadVector())) { + // Handle the case when the allocation input to VectorBoxNode is a phi + // but the vector input is not, which can definitely be the case if the + // vector input has been value-numbered. It seems to be safe to do by + // construction because VectorBoxNode and VectorBoxAllocate come in a + // specific order as a result of expanding an intrinsic call. After that, if + // any of the inputs to VectorBoxNode are value-numbered they can only + // move up and are guaranteed to dominate. + Node* new_phi = new PhiNode(vbox->as_Phi()->region(), box_type); + for (uint i = 1; i < vbox->req(); i++) { + Node* new_box = expand_vbox_node_helper(vbox->in(i), vect, box_type, vect_type); + new_phi->set_req(i, new_box); + } + new_phi = C->initial_gvn()->transform(new_phi); + return new_phi; } else if (vbox->is_Proj() && vbox->in(0)->Opcode() == Op_VectorBoxAllocate) { VectorBoxAllocateNode* vbox_alloc = static_cast(vbox->in(0)); return expand_vbox_alloc_node(vbox_alloc, vect, box_type, vect_type); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/prims/jvm.cpp openjdk-17-17.0.4+8/src/hotspot/share/prims/jvm.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/prims/jvm.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/prims/jvm.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -2909,6 +2909,9 @@ assert(native_thread != NULL, "Starting null thread?"); if (native_thread->osthread() == NULL) { + ResourceMark rm(thread); + log_warning(os, thread)("Failed to start the native thread for java.lang.Thread \"%s\"", + JavaThread::name_for(JNIHandles::resolve_non_null(jthread))); // No one should hold a reference to the 'native_thread'. native_thread->smr_delete(); if (JvmtiExport::should_post_resource_exhausted()) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/prims/vectorSupport.cpp openjdk-17-17.0.4+8/src/hotspot/share/prims/vectorSupport.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/prims/vectorSupport.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/prims/vectorSupport.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -171,17 +171,17 @@ return allocate_vector_payload_helper(ik, fr, reg_map, location, THREAD); // safepoint } #ifdef ASSERT - // Other payload values are: 'oop' type location and Scalar-replaced boxed vector representation. + // Other payload values are: 'oop' type location and scalar-replaced boxed vector representation. // They will be processed in Deoptimization::reassign_fields() after all objects are reallocated. else { Location::Type loc_type = location.type(); assert(loc_type == Location::oop || loc_type == Location::narrowoop, "expected 'oop'(%d) or 'narrowoop'(%d) types location but got: %d", Location::oop, Location::narrowoop, loc_type); } - } else if (!payload->is_object()) { + } else if (!payload->is_object() && !payload->is_constant_oop()) { stringStream ss; payload->print_on(&ss); - assert(payload->is_object(), "expected 'object' value for scalar-replaced boxed vector but got: %s", ss.as_string()); + assert(false, "expected 'object' value for scalar-replaced boxed vector but got: %s", ss.as_string()); #endif } return Handle(THREAD, nullptr); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/prims/whitebox.cpp openjdk-17-17.0.4+8/src/hotspot/share/prims/whitebox.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/prims/whitebox.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/prims/whitebox.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -2006,6 +2006,14 @@ #endif // INCLUDE_JFR WB_END +WB_ENTRY(jboolean, WB_IsDTraceIncluded(JNIEnv* env)) +#if defined(DTRACE_ENABLED) + return true; +#else + return false; +#endif // DTRACE_ENABLED +WB_END + #if INCLUDE_CDS WB_ENTRY(jint, WB_GetOffsetForName(JNIEnv* env, jobject o, jstring name)) @@ -2586,6 +2594,7 @@ {CC"areOpenArchiveHeapObjectsMapped", CC"()Z", (void*)&WB_AreOpenArchiveHeapObjectsMapped}, {CC"isCDSIncluded", CC"()Z", (void*)&WB_IsCDSIncluded }, {CC"isJFRIncluded", CC"()Z", (void*)&WB_IsJFRIncluded }, + {CC"isDTraceIncluded", CC"()Z", (void*)&WB_IsDTraceIncluded }, {CC"isC2OrJVMCIIncluded", CC"()Z", (void*)&WB_isC2OrJVMCIIncluded }, {CC"isJVMCISupportedByGC", CC"()Z", (void*)&WB_IsJVMCISupportedByGC}, {CC"isJavaHeapArchiveSupported", CC"()Z", (void*)&WB_IsJavaHeapArchiveSupported }, diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/abstract_vm_version.cpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/abstract_vm_version.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/abstract_vm_version.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/abstract_vm_version.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,11 +198,7 @@ #ifndef HOTSPOT_BUILD_COMPILER #ifdef _MSC_VER - #if _MSC_VER == 1600 - #define HOTSPOT_BUILD_COMPILER "MS VC++ 10.0 (VS2010)" - #elif _MSC_VER == 1700 - #define HOTSPOT_BUILD_COMPILER "MS VC++ 11.0 (VS2012)" - #elif _MSC_VER == 1800 + #if _MSC_VER == 1800 #define HOTSPOT_BUILD_COMPILER "MS VC++ 12.0 (VS2013)" #elif _MSC_VER == 1900 #define HOTSPOT_BUILD_COMPILER "MS VC++ 14.0 (VS2015)" @@ -238,6 +234,10 @@ #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.8 / 16.9 (VS2019)" #elif _MSC_VER == 1929 #define HOTSPOT_BUILD_COMPILER "MS VC++ 16.10 / 16.11 (VS2019)" + #elif _MSC_VER == 1930 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.0 (VS2022)" + #elif _MSC_VER == 1931 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.1 (VS2022)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/arguments.cpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/arguments.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/arguments.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/arguments.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -2881,6 +2881,18 @@ jio_fprintf(defaultStream::error_stream(), "ExtendedDTraceProbes flag is not applicable for this configuration\n"); return JNI_EINVAL; + } else if (match_option(option, "-XX:+DTraceMethodProbes")) { + jio_fprintf(defaultStream::error_stream(), + "DTraceMethodProbes flag is not applicable for this configuration\n"); + return JNI_EINVAL; + } else if (match_option(option, "-XX:+DTraceAllocProbes")) { + jio_fprintf(defaultStream::error_stream(), + "DTraceAllocProbes flag is not applicable for this configuration\n"); + return JNI_EINVAL; + } else if (match_option(option, "-XX:+DTraceMonitorProbes")) { + jio_fprintf(defaultStream::error_stream(), + "DTraceMonitorProbes flag is not applicable for this configuration\n"); + return JNI_EINVAL; #endif // defined(DTRACE_ENABLED) #ifdef ASSERT } else if (match_option(option, "-XX:+FullGCALot")) { diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/deoptimization.cpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/deoptimization.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/deoptimization.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/deoptimization.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -683,6 +683,21 @@ assert(f->is_interpreted_frame(), "must be interpreted"); } +#ifndef PRODUCT +static bool falls_through(Bytecodes::Code bc) { + switch (bc) { + // List may be incomplete. Here we really only care about bytecodes where compiled code + // can deoptimize. + case Bytecodes::_goto: + case Bytecodes::_goto_w: + case Bytecodes::_athrow: + return false; + default: + return true; + } +} +#endif + // Return BasicType of value being returned JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode)) @@ -791,7 +806,7 @@ // calls. It seems to be hard to tell whether the compiler // has emitted debug information matching the "state before" // a given bytecode or the state after, so we try both - if (!Bytecodes::is_invoke(cur_code) && cur_code != Bytecodes::_athrow) { + if (!Bytecodes::is_invoke(cur_code) && falls_through(cur_code)) { // Get expression stack size for the next bytecode InterpreterOopMap next_mask; OopMapCache::compute_one_oop_map(mh, str.bci(), &next_mask); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/objectMonitor.cpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/objectMonitor.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/objectMonitor.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/objectMonitor.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -233,19 +233,6 @@ // * See also http://blogs.sun.com/dave -void* ObjectMonitor::operator new (size_t size) throw() { - return AllocateHeap(size, mtInternal); -} -void* ObjectMonitor::operator new[] (size_t size) throw() { - return operator new (size); -} -void ObjectMonitor::operator delete(void* p) { - FreeHeap(p); -} -void ObjectMonitor::operator delete[] (void *p) { - operator delete(p); -} - // Check that object() and set_object() are called from the right context: static void check_object_context() { #ifdef ASSERT diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/objectMonitor.hpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/objectMonitor.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/objectMonitor.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/objectMonitor.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -203,11 +203,6 @@ static int Knob_SpinLimit; - void* operator new (size_t size) throw(); - void* operator new[] (size_t size) throw(); - void operator delete(void* p); - void operator delete[] (void* p); - // TODO-FIXME: the "offset" routines should return a type of off_t instead of int ... // ByteSize would also be an appropriate type. static int header_offset_in_bytes() { return offset_of(ObjectMonitor, _header); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/stubCodeGenerator.cpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/stubCodeGenerator.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/stubCodeGenerator.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/stubCodeGenerator.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -69,7 +69,7 @@ // Implementation of StubCodeGenerator StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, bool print_code) { - _masm = new MacroAssembler(code ); + _masm = new MacroAssembler(code); _print_code = PrintStubCode || print_code; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/sweeper.cpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/sweeper.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/sweeper.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/sweeper.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -229,19 +229,19 @@ /** * Wakes up the sweeper thread to sweep if code cache space runs low */ -void NMethodSweeper::report_allocation(int code_blob_type) { - if (should_start_aggressive_sweep(code_blob_type)) { +void NMethodSweeper::report_allocation() { + if (should_start_aggressive_sweep()) { MonitorLocker waiter(CodeSweeper_lock, Mutex::_no_safepoint_check_flag); _should_sweep = true; CodeSweeper_lock->notify(); } } -bool NMethodSweeper::should_start_aggressive_sweep(int code_blob_type) { +bool NMethodSweeper::should_start_aggressive_sweep() { // Makes sure that we do not invoke the sweeper too often during startup. double start_threshold = 100.0 / (double)StartAggressiveSweepingAt; double aggressive_sweep_threshold = MAX2(start_threshold, 1.1); - return (CodeCache::reverse_free_ratio(code_blob_type) >= aggressive_sweep_threshold); + return (CodeCache::reverse_free_ratio() >= aggressive_sweep_threshold); } /** @@ -546,8 +546,7 @@ // ReservedCodeCacheSize int reset_val = hotness_counter_reset_val(); int time_since_reset = reset_val - nm->hotness_counter(); - int code_blob_type = CodeCache::get_code_blob_type(nm); - double threshold = -reset_val + (CodeCache::reverse_free_ratio(code_blob_type) * NmethodSweepActivity); + double threshold = -reset_val + (CodeCache::reverse_free_ratio() * NmethodSweepActivity); // The less free space in the code cache we have - the bigger reverse_free_ratio() is. // I.e., 'threshold' increases with lower available space in the code cache and a higher // NmethodSweepActivity. If the current hotness counter - which decreases from its initial diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/sweeper.hpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/sweeper.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/sweeper.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/sweeper.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,11 +113,11 @@ static CodeBlobClosure* prepare_mark_active_nmethods(); static void sweeper_loop(); - static bool should_start_aggressive_sweep(int code_blob_type); + static bool should_start_aggressive_sweep(); static void force_sweep(); static int hotness_counter_reset_val(); static void report_state_change(nmethod* nm); - static void report_allocation(int code_blob_type); // Possibly start the sweeper thread. + static void report_allocation(); // Possibly start the sweeper thread. static void possibly_flush(nmethod* nm); static void print(outputStream* out); // Printing/debugging static void print() { print(tty); } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/thread.cpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/thread.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/thread.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/thread.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -479,6 +479,13 @@ return true; } + // If the target hasn't been started yet then it is trivially + // "protected". We assume the caller is the thread that will do + // the starting. + if (p->osthread() == NULL || p->osthread()->get_state() <= INITIALIZED) { + return true; + } + // Now make the simple checks based on who the caller is: Thread* current_thread = Thread::current(); if (current_thread == p || Threads_lock->owner() == current_thread) { @@ -2190,7 +2197,7 @@ } // Returns a non-NULL representation of this thread's name, or a suitable -// descriptive string if there is no set name +// descriptive string if there is no set name. const char* JavaThread::get_thread_name_string(char* buf, int buflen) const { const char* name_str; oop thread_obj = threadObj(); @@ -2214,6 +2221,19 @@ return name_str; } +// Helper to extract the name from the thread oop for logging. +const char* JavaThread::name_for(oop thread_obj) { + assert(thread_obj != NULL, "precondition"); + oop name = java_lang_Thread::name(thread_obj); + const char* name_str; + if (name != NULL) { + name_str = java_lang_String::as_utf8_string(name); + } else { + name_str = ""; + } + return name_str; +} + void JavaThread::prepare(jobject jni_thread, ThreadPriority prio) { assert(Threads_lock->owner() == Thread::current(), "must have threads lock"); diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/runtime/thread.hpp openjdk-17-17.0.4+8/src/hotspot/share/runtime/thread.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/runtime/thread.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/runtime/thread.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -1376,6 +1376,7 @@ // Misc. operations char* name() const { return (char*)get_thread_name(); } + static const char* name_for(oop thread_obj); void print_on(outputStream* st, bool print_extended_info) const; void print_on(outputStream* st) const { print_on(st, false); } void print() const; diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/services/diagnosticArgument.cpp openjdk-17-17.0.4+8/src/hotspot/share/services/diagnosticArgument.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/services/diagnosticArgument.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/services/diagnosticArgument.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * 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,6 +28,7 @@ #include "memory/resourceArea.hpp" #include "runtime/thread.hpp" #include "services/diagnosticArgument.hpp" +#include "utilities/globalDefinitions.hpp" StringArrayArgument::StringArrayArgument() { _array = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray(32, mtServiceability); @@ -114,13 +115,12 @@ || sscanf(str, JLONG_FORMAT "%n", &_value, &scanned) != 1 || (size_t)scanned != len) { - ResourceMark rm; - - char* buf = NEW_RESOURCE_ARRAY(char, len + 1); - strncpy(buf, str, len); - buf[len] = '\0'; + const int maxprint = 64; Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(), - "Integer parsing error in command argument '%s'. Could not parse: %s.\n", _name, buf); + "Integer parsing error in command argument '%s'. Could not parse: %.*s%s.\n", _name, + MIN2((int)len, maxprint), + (str == NULL ? "" : str), + (len > maxprint ? "..." : "")); } } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/utilities/constantTag.hpp openjdk-17-17.0.4+8/src/hotspot/share/utilities/constantTag.hpp --- openjdk-17-17.0.3+7/src/hotspot/share/utilities/constantTag.hpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/utilities/constantTag.hpp 2022-07-14 08:05:38.000000000 +0000 @@ -86,6 +86,13 @@ return _tag == JVM_CONSTANT_DynamicInError; } + bool is_in_error() const { + return is_unresolved_klass_in_error() || + is_method_handle_in_error() || + is_method_type_in_error() || + is_dynamic_constant_in_error(); + } + bool is_klass_index() const { return _tag == JVM_CONSTANT_ClassIndex; } bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; } @@ -121,18 +128,24 @@ _tag = tag; } - static constantTag ofBasicType(BasicType bt) { - if (is_subword_type(bt)) bt = T_INT; + static jbyte type2tag(BasicType bt) { + if (is_subword_type(bt)) { + bt = T_INT; + } + if (bt == T_ARRAY) { + bt = T_OBJECT; + } switch (bt) { - case T_OBJECT: return constantTag(JVM_CONSTANT_String); - case T_INT: return constantTag(JVM_CONSTANT_Integer); - case T_LONG: return constantTag(JVM_CONSTANT_Long); - case T_FLOAT: return constantTag(JVM_CONSTANT_Float); - case T_DOUBLE: return constantTag(JVM_CONSTANT_Double); - default: break; + case T_INT: return JVM_CONSTANT_Integer; + case T_LONG: return JVM_CONSTANT_Long; + case T_FLOAT: return JVM_CONSTANT_Float; + case T_DOUBLE: return JVM_CONSTANT_Double; + case T_OBJECT: return JVM_CONSTANT_String; + + default: + assert(false, "not supported: %s", type2name(bt)); + return JVM_CONSTANT_Invalid; } - assert(false, "bad basic type for tag"); - return constantTag(); } jbyte value() const { return _tag; } diff -Nru openjdk-17-17.0.3+7/src/hotspot/share/utilities/vmError.cpp openjdk-17-17.0.4+8/src/hotspot/share/utilities/vmError.cpp --- openjdk-17-17.0.3+7/src/hotspot/share/utilities/vmError.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/hotspot/share/utilities/vmError.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -97,7 +97,8 @@ // Env variables that are defined on Linux/BSD "LD_LIBRARY_PATH", "LD_PRELOAD", "SHELL", "DISPLAY", "HOSTTYPE", "OSTYPE", "ARCH", "MACHTYPE", - "LANG", "LC_ALL", "LC_CTYPE", "TZ", + "LANG", "LC_ALL", "LC_CTYPE", "LC_NUMERIC", "LC_TIME", + "TERM", "TMPDIR", "TZ", // defined on AIX "LIBPATH", "LDR_PRELOAD", "LDR_PRELOAD64", @@ -111,7 +112,7 @@ "DYLD_INSERT_LIBRARIES", // defined on Windows - "OS", "PROCESSOR_IDENTIFIER", "_ALT_JAVA_HOME_DIR", + "OS", "PROCESSOR_IDENTIFIER", "_ALT_JAVA_HOME_DIR", "TMP", "TEMP", (const char *)0 }; diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/io/ClassCache.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/io/ClassCache.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/io/ClassCache.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/io/ClassCache.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 java.io; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.Objects; + +// Maps Class instances to values of type T. Under memory pressure, the +// mapping is released (under soft references GC policy) and would be +// recomputed the next time it is queried. The mapping is bound to the +// lifetime of the class: when the class is unloaded, the mapping is +// removed too. +abstract class ClassCache { + + private static class CacheRef extends SoftReference { + private final Class type; + private T strongReferent; + + CacheRef(T referent, ReferenceQueue queue, Class type) { + super(referent, queue); + this.type = type; + this.strongReferent = referent; + } + + Class getType() { + return type; + } + + T getStrong() { + return strongReferent; + } + + void clearStrong() { + strongReferent = null; + } + } + + private final ReferenceQueue queue; + private final ClassValue> map; + + protected abstract T computeValue(Class cl); + + protected ClassCache() { + queue = new ReferenceQueue<>(); + map = new ClassValue<>() { + @Override + protected CacheRef computeValue(Class type) { + T v = ClassCache.this.computeValue(type); + Objects.requireNonNull(v); + return new CacheRef<>(v, queue, type); + } + }; + } + + T get(Class cl) { + while (true) { + processQueue(); + + CacheRef ref = map.get(cl); + + // Case 1: A recently created CacheRef. + // We might still have strong referent, and can return it. + // This guarantees progress for at least one thread on every CacheRef. + // Clear the strong referent before returning to make the cache soft. + T strongVal = ref.getStrong(); + if (strongVal != null) { + ref.clearStrong(); + return strongVal; + } + + // Case 2: Older or recently cleared CacheRef. + // Check if its soft referent is still available, and return it. + T val = ref.get(); + if (val != null) { + return val; + } + + // Case 3: The reference was cleared. + // Clear the mapping and retry. + map.remove(cl); + } + } + + private void processQueue() { + Reference ref; + while((ref = queue.poll()) != null) { + CacheRef cacheRef = (CacheRef)ref; + map.remove(cacheRef.getType()); + } + } +} diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/io/ObjectInputStream.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/io/ObjectInputStream.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/io/ObjectInputStream.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/io/ObjectInputStream.java 2022-07-14 08:05:38.000000000 +0000 @@ -26,11 +26,9 @@ package java.io; import java.io.ObjectInputFilter.Config; -import java.io.ObjectStreamClass.WeakClassKey; import java.io.ObjectStreamClass.RecordSupport; import java.lang.System.Logger; import java.lang.invoke.MethodHandle; -import java.lang.ref.ReferenceQueue; import java.lang.reflect.Array; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Modifier; @@ -43,10 +41,6 @@ import java.util.Arrays; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static java.io.ObjectStreamClass.processQueue; import jdk.internal.access.SharedSecrets; import jdk.internal.event.DeserializationEvent; @@ -276,12 +270,13 @@ private static class Caches { /** cache of subclass security audit results */ - static final ConcurrentMap subclassAudits = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to audited subclasses */ - static final ReferenceQueue> subclassAuditsQueue = - new ReferenceQueue<>(); + static final ClassValue subclassAudits = + new ClassValue<>() { + @Override + protected Boolean computeValue(Class type) { + return auditSubclass(type); + } + }; /** * Property to permit setting a filter after objects @@ -1616,13 +1611,7 @@ if (sm == null) { return; } - processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); - WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); - Boolean result = Caches.subclassAudits.get(key); - if (result == null) { - result = auditSubclass(cl); - Caches.subclassAudits.putIfAbsent(key, result); - } + boolean result = Caches.subclassAudits.get(cl); if (!result) { sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/io/ObjectOutputStream.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/io/ObjectOutputStream.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/io/ObjectOutputStream.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/io/ObjectOutputStream.java 2022-07-14 08:05:38.000000000 +0000 @@ -25,17 +25,12 @@ package java.io; -import java.io.ObjectStreamClass.WeakClassKey; -import java.lang.ref.ReferenceQueue; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.StringJoiner; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import static java.io.ObjectStreamClass.processQueue; import sun.reflect.misc.ReflectUtil; /** @@ -169,12 +164,13 @@ private static class Caches { /** cache of subclass security audit results */ - static final ConcurrentMap subclassAudits = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to audited subclasses */ - static final ReferenceQueue> subclassAuditsQueue = - new ReferenceQueue<>(); + static final ClassValue subclassAudits = + new ClassValue<>() { + @Override + protected Boolean computeValue(Class type) { + return auditSubclass(type); + } + }; } /** filter stream for handling block data conversion */ @@ -1060,13 +1056,7 @@ if (sm == null) { return; } - processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); - WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); - Boolean result = Caches.subclassAudits.get(key); - if (result == null) { - result = auditSubclass(cl); - Caches.subclassAudits.putIfAbsent(key, result); - } + boolean result = Caches.subclassAudits.get(cl); if (!result) { sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/io/ObjectStreamClass.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/io/ObjectStreamClass.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/io/ObjectStreamClass.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/io/ObjectStreamClass.java 2022-07-14 08:05:38.000000000 +0000 @@ -28,10 +28,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -59,7 +55,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -108,19 +103,22 @@ private static class Caches { /** cache mapping local classes -> descriptors */ - static final ConcurrentMap> localDescs = - new ConcurrentHashMap<>(); + static final ClassCache localDescs = + new ClassCache<>() { + @Override + protected ObjectStreamClass computeValue(Class type) { + return new ObjectStreamClass(type); + } + }; /** cache mapping field group/local desc pairs -> field reflectors */ - static final ConcurrentMap> reflectors = - new ConcurrentHashMap<>(); - - /** queue for WeakReferences to local classes */ - private static final ReferenceQueue> localDescsQueue = - new ReferenceQueue<>(); - /** queue for WeakReferences to field reflectors keys */ - private static final ReferenceQueue> reflectorsQueue = - new ReferenceQueue<>(); + static final ClassCache> reflectors = + new ClassCache<>() { + @Override + protected Map computeValue(Class type) { + return new ConcurrentHashMap<>(); + } + }; } /** class associated with this descriptor (if any) */ @@ -362,136 +360,7 @@ if (!(all || Serializable.class.isAssignableFrom(cl))) { return null; } - processQueue(Caches.localDescsQueue, Caches.localDescs); - WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); - Reference ref = Caches.localDescs.get(key); - Object entry = null; - if (ref != null) { - entry = ref.get(); - } - EntryFuture future = null; - if (entry == null) { - EntryFuture newEntry = new EntryFuture(); - Reference newRef = new SoftReference<>(newEntry); - do { - if (ref != null) { - Caches.localDescs.remove(key, ref); - } - ref = Caches.localDescs.putIfAbsent(key, newRef); - if (ref != null) { - entry = ref.get(); - } - } while (ref != null && entry == null); - if (entry == null) { - future = newEntry; - } - } - - if (entry instanceof ObjectStreamClass) { // check common case first - return (ObjectStreamClass) entry; - } - if (entry instanceof EntryFuture) { - future = (EntryFuture) entry; - if (future.getOwner() == Thread.currentThread()) { - /* - * Handle nested call situation described by 4803747: waiting - * for future value to be set by a lookup() call further up the - * stack will result in deadlock, so calculate and set the - * future value here instead. - */ - entry = null; - } else { - entry = future.get(); - } - } - if (entry == null) { - try { - entry = new ObjectStreamClass(cl); - } catch (Throwable th) { - entry = th; - } - if (future.set(entry)) { - Caches.localDescs.put(key, new SoftReference<>(entry)); - } else { - // nested lookup call already set future - entry = future.get(); - } - } - - if (entry instanceof ObjectStreamClass) { - return (ObjectStreamClass) entry; - } else if (entry instanceof RuntimeException) { - throw (RuntimeException) entry; - } else if (entry instanceof Error) { - throw (Error) entry; - } else { - throw new InternalError("unexpected entry: " + entry); - } - } - - /** - * Placeholder used in class descriptor and field reflector lookup tables - * for an entry in the process of being initialized. (Internal) callers - * which receive an EntryFuture belonging to another thread as the result - * of a lookup should call the get() method of the EntryFuture; this will - * return the actual entry once it is ready for use and has been set(). To - * conserve objects, EntryFutures synchronize on themselves. - */ - private static class EntryFuture { - - private static final Object unset = new Object(); - private final Thread owner = Thread.currentThread(); - private Object entry = unset; - - /** - * Attempts to set the value contained by this EntryFuture. If the - * EntryFuture's value has not been set already, then the value is - * saved, any callers blocked in the get() method are notified, and - * true is returned. If the value has already been set, then no saving - * or notification occurs, and false is returned. - */ - synchronized boolean set(Object entry) { - if (this.entry != unset) { - return false; - } - this.entry = entry; - notifyAll(); - return true; - } - - /** - * Returns the value contained by this EntryFuture, blocking if - * necessary until a value is set. - */ - @SuppressWarnings("removal") - synchronized Object get() { - boolean interrupted = false; - while (entry == unset) { - try { - wait(); - } catch (InterruptedException ex) { - interrupted = true; - } - } - if (interrupted) { - AccessController.doPrivileged( - new PrivilegedAction<>() { - public Void run() { - Thread.currentThread().interrupt(); - return null; - } - } - ); - } - return entry; - } - - /** - * Returns the thread that created this EntryFuture. - */ - Thread getOwner() { - return owner; - } + return Caches.localDescs.get(cl); } /** @@ -2250,82 +2119,39 @@ { // class irrelevant if no fields Class cl = (localDesc != null && fields.length > 0) ? - localDesc.cl : null; - processQueue(Caches.reflectorsQueue, Caches.reflectors); - FieldReflectorKey key = new FieldReflectorKey(cl, fields, - Caches.reflectorsQueue); - Reference ref = Caches.reflectors.get(key); - Object entry = null; - if (ref != null) { - entry = ref.get(); - } - EntryFuture future = null; - if (entry == null) { - EntryFuture newEntry = new EntryFuture(); - Reference newRef = new SoftReference<>(newEntry); - do { - if (ref != null) { - Caches.reflectors.remove(key, ref); - } - ref = Caches.reflectors.putIfAbsent(key, newRef); - if (ref != null) { - entry = ref.get(); - } - } while (ref != null && entry == null); - if (entry == null) { - future = newEntry; - } - } + localDesc.cl : Void.class; - if (entry instanceof FieldReflector) { // check common case first - return (FieldReflector) entry; - } else if (entry instanceof EntryFuture) { - entry = ((EntryFuture) entry).get(); - } else if (entry == null) { - try { - entry = new FieldReflector(matchFields(fields, localDesc)); - } catch (Throwable th) { - entry = th; - } - future.set(entry); - Caches.reflectors.put(key, new SoftReference<>(entry)); - } - - if (entry instanceof FieldReflector) { - return (FieldReflector) entry; - } else if (entry instanceof InvalidClassException) { - throw (InvalidClassException) entry; - } else if (entry instanceof RuntimeException) { - throw (RuntimeException) entry; - } else if (entry instanceof Error) { - throw (Error) entry; - } else { - throw new InternalError("unexpected entry: " + entry); + var clReflectors = Caches.reflectors.get(cl); + var key = new FieldReflectorKey(fields); + var reflector = clReflectors.get(key); + if (reflector == null) { + reflector = new FieldReflector(matchFields(fields, localDesc)); + var oldReflector = clReflectors.putIfAbsent(key, reflector); + if (oldReflector != null) { + reflector = oldReflector; + } } + return reflector; } /** * FieldReflector cache lookup key. Keys are considered equal if they - * refer to the same class and equivalent field formats. + * refer to equivalent field formats. */ - private static class FieldReflectorKey extends WeakReference> { + private static class FieldReflectorKey { private final String[] sigs; private final int hash; - private final boolean nullClass; - FieldReflectorKey(Class cl, ObjectStreamField[] fields, - ReferenceQueue> queue) + FieldReflectorKey(ObjectStreamField[] fields) { - super(cl, queue); - nullClass = (cl == null); sigs = new String[2 * fields.length]; for (int i = 0, j = 0; i < fields.length; i++) { ObjectStreamField f = fields[i]; sigs[j++] = f.getName(); sigs[j++] = f.getSignature(); } - hash = System.identityHashCode(cl) + Arrays.hashCode(sigs); + hash = Arrays.hashCode(sigs); } public int hashCode() { @@ -2333,19 +2159,9 @@ } public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof FieldReflectorKey other) { - Class referent; - return (nullClass ? other.nullClass - : ((referent = get()) != null) && - (other.refersTo(referent))) && - Arrays.equals(sigs, other.sigs); - } else { - return false; - } + return obj == this || + obj instanceof FieldReflectorKey other && + Arrays.equals(sigs, other.sigs); } } @@ -2410,68 +2226,6 @@ } /** - * Removes from the specified map any keys that have been enqueued - * on the specified reference queue. - */ - static void processQueue(ReferenceQueue> queue, - ConcurrentMap>, ?> map) - { - Reference> ref; - while((ref = queue.poll()) != null) { - map.remove(ref); - } - } - - /** - * Weak key for Class objects. - * - **/ - static class WeakClassKey extends WeakReference> { - /** - * saved value of the referent's identity hash code, to maintain - * a consistent hash code after the referent has been cleared - */ - private final int hash; - - /** - * Create a new WeakClassKey to the given object, registered - * with a queue. - */ - WeakClassKey(Class cl, ReferenceQueue> refQueue) { - super(cl, refQueue); - hash = System.identityHashCode(cl); - } - - /** - * Returns the identity hash code of the original referent. - */ - public int hashCode() { - return hash; - } - - /** - * Returns true if the given object is this identical - * WeakClassKey instance, or, if this object's referent has not - * been cleared, if the given object is another WeakClassKey - * instance with the identical non-null referent as this one. - */ - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof WeakClassKey) { - Class referent = get(); - return (referent != null) && - (((WeakClassKey) obj).refersTo(referent)); - } else { - return false; - } - } - } - - /** * A LRA cache of record deserialization constructors. */ @SuppressWarnings("serial") diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java 2022-07-14 08:05:38.000000000 +0000 @@ -682,6 +682,7 @@ } private static MemberName resolveFrom(String name, MethodType type, Class holder) { + assert(!UNSAFE.shouldBeInitialized(holder)) : holder + "not initialized"; MemberName member = new MemberName(holder, name, type, REF_invokeStatic); MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder, LM_TRUSTED); traceLambdaForm(name, type, holder, resolvedMember); diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/lang/invoke/VarForm.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/lang/invoke/VarForm.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/lang/invoke/VarForm.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/lang/invoke/VarForm.java 2022-07-14 08:05:38.000000000 +0000 @@ -109,9 +109,14 @@ @ForceInline final MemberName getMemberName(int mode) { - MemberName mn = getMemberNameOrNull(mode); + // Can be simplified by calling getMemberNameOrNull, but written in this + // form to improve interpreter/coldpath performance. + MemberName mn = memberName_table[mode]; if (mn == null) { - throw new UnsupportedOperationException(); + mn = resolveMemberName(mode); + if (mn == null) { + throw new UnsupportedOperationException(); + } } return mn; } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/net/doc-files/net-properties.html openjdk-17-17.0.4+8/src/java.base/share/classes/java/net/doc-files/net-properties.html --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/net/doc-files/net-properties.html 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/net/doc-files/net-properties.html 2022-07-14 08:05:38.000000000 +0000 @@ -214,6 +214,22 @@ property is defined, then its value will be used as the domain name.

+
  • {@systemProperty jdk.https.negotiate.cbt} (default: <never>)
    + This controls the generation and sending of TLS channel binding tokens (CBT) when Kerberos + or the Negotiate authentication scheme using Kerberos are employed over HTTPS with + {@code HttpsURLConnection}. There are three possible settings:

    +
      +
    1. "never". This is also the default value if the property is not set. In this case, + CBTs are never sent.

      +
    2. "always". CBTs are sent for all Kerberos authentication attempts over HTTPS.

      +
    3. "domain:<comma separated domain list>" Each domain in the list specifies destination + host or hosts for which a CBT is sent. Domains can be single hosts like foo, or foo.com, + or literal IP addresses as specified in RFC 2732, or wildcards like *.foo.com which matches + all hosts under foo.com and its sub-domains. CBTs are not sent to any destinations + that don't match one of the list entries

      +
    +

    The channel binding tokens generated are of the type "tls-server-end-point" as defined in + RFC 5929.

    All these properties are checked only once at startup.

    diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/net/HostPortrange.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/net/HostPortrange.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/net/HostPortrange.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/net/HostPortrange.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,7 +137,7 @@ } this.ipv4 = this.literal = ipv4; if (ipv4) { - byte[] ip = IPAddressUtil.textToNumericFormatV4(hoststr); + byte[] ip = IPAddressUtil.validateNumericFormatV4(hoststr); if (ip == null) { throw new IllegalArgumentException("illegal IPv4 address"); } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/net/InetAddress.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/net/InetAddress.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/net/InetAddress.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/net/InetAddress.java 2022-07-14 08:05:38.000000000 +0000 @@ -1104,7 +1104,11 @@ private byte [] createAddressByteArray(String addrStr) { byte[] addrArray; // check if IPV4 address - most likely - addrArray = IPAddressUtil.textToNumericFormatV4(addrStr); + try { + addrArray = IPAddressUtil.validateNumericFormatV4(addrStr); + } catch (IllegalArgumentException iae) { + return null; + } if (addrArray == null) { addrArray = IPAddressUtil.textToNumericFormatV6(addrStr); } @@ -1323,13 +1327,19 @@ } // if host is an IP address, we won't do further lookup - if (Character.digit(host.charAt(0), 16) != -1 + if (IPAddressUtil.digit(host.charAt(0), 16) != -1 || (host.charAt(0) == ':')) { - byte[] addr = null; + byte[] addr; int numericZone = -1; String ifname = null; // see if it is IPv4 address - addr = IPAddressUtil.textToNumericFormatV4(host); + try { + addr = IPAddressUtil.validateNumericFormatV4(host); + } catch (IllegalArgumentException iae) { + var uhe = new UnknownHostException(host); + uhe.initCause(iae); + throw uhe; + } if (addr == null) { // This is supposed to be an IPv6 literal // Check if a numeric or string zone id is present diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/net/SocketPermission.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/net/SocketPermission.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/net/SocketPermission.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/net/SocketPermission.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -470,7 +470,7 @@ if (!host.isEmpty()) { // see if we are being initialized with an IP address. char ch = host.charAt(0); - if (ch == ':' || Character.digit(ch, 16) != -1) { + if (ch == ':' || IPAddressUtil.digit(ch, 16) != -1) { byte ip[] = IPAddressUtil.textToNumericFormatV4(host); if (ip == null) { ip = IPAddressUtil.textToNumericFormatV6(host); diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/text/DecimalFormat.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/text/DecimalFormat.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/text/DecimalFormat.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/text/DecimalFormat.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3210,16 +3210,18 @@ for (i = digitCount; i > 0; --i) { if (i != digitCount && isGroupingUsed() && groupingSize != 0 && i % groupingSize == 0) { - result.append(localized ? symbols.getGroupingSeparator() : - PATTERN_GROUPING_SEPARATOR); + result.append(localized ? + (isCurrencyFormat ? symbols.getMonetaryGroupingSeparator() : symbols.getGroupingSeparator()) : + PATTERN_GROUPING_SEPARATOR); } result.append(i <= getMinimumIntegerDigits() ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT) : (localized ? symbols.getDigit() : PATTERN_DIGIT)); } if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) - result.append(localized ? symbols.getDecimalSeparator() : - PATTERN_DECIMAL_SEPARATOR); + result.append(localized ? + (isCurrencyFormat ? symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator()) : + PATTERN_DECIMAL_SEPARATOR); for (i = 0; i < getMaximumFractionDigits(); ++i) { if (i < getMinimumFractionDigits()) { result.append(localized ? symbols.getZeroDigit() : diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/jar/JarVerifier.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/jar/JarVerifier.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/jar/JarVerifier.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/jar/JarVerifier.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,6 +96,10 @@ /** collect -DIGEST-MANIFEST values for deny list */ private List manifestDigests; + /* A cache mapping code signers to the algorithms used to digest jar + entries, and whether or not the algorithms are permitted. */ + private Map> signersToAlgs; + public JarVerifier(String name, byte rawBytes[]) { manifestName = name; manifestRawBytes = rawBytes; @@ -105,6 +109,7 @@ pendingBlocks = new ArrayList<>(); baos = new ByteArrayOutputStream(); manifestDigests = new ArrayList<>(); + signersToAlgs = new HashMap<>(); } /** @@ -244,7 +249,8 @@ if (!parsingBlockOrSF) { JarEntry je = mev.getEntry(); if ((je != null) && (je.signers == null)) { - je.signers = mev.verify(verifiedSigners, sigFileSigners); + je.signers = mev.verify(verifiedSigners, sigFileSigners, + signersToAlgs); je.certs = mapSignersToCertArray(je.signers); } } else { diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,7 +107,9 @@ sb.append(pattern); if (index >= 0 && pattern != null && index < pattern.length()) { sb.append(System.lineSeparator()); - for (int i = 0; i < index; i++) sb.append(' '); + for (int i = 0; i < index; i++) { + sb.append((pattern.charAt(i) == '\t') ? '\t' : ' '); + } sb.append('^'); } return sb.toString(); diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/zip/Deflater.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/zip/Deflater.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/zip/Deflater.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/zip/Deflater.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -898,6 +898,16 @@ throw new NullPointerException("Deflater has been closed"); } + /** + * Returns the value of 'finish' flag. + * 'finish' will be set to true if def.finish() method is called. + */ + boolean shouldFinish() { + synchronized (zsRef) { + return finish; + } + } + private static native long init(int level, int strategy, boolean nowrap); private static native void setDictionary(long addr, byte[] b, int off, int len); diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -220,9 +220,15 @@ */ public void finish() throws IOException { if (!def.finished()) { - def.finish(); - while (!def.finished()) { - deflate(); + try{ + def.finish(); + while (!def.finished()) { + deflate(); + } + } catch(IOException e) { + if (usesDefaultDeflater) + def.end(); + throw e; } } } @@ -234,9 +240,12 @@ */ public void close() throws IOException { if (!closed) { - finish(); - if (usesDefaultDeflater) - def.end(); + try { + finish(); + } finally { + if (usesDefaultDeflater) + def.end(); + } out.close(); closed = true; } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java 2022-07-14 08:05:38.000000000 +0000 @@ -157,24 +157,30 @@ */ public void finish() throws IOException { if (!def.finished()) { - def.finish(); - while (!def.finished()) { - int len = def.deflate(buf, 0, buf.length); - if (def.finished() && len <= buf.length - TRAILER_SIZE) { - // last deflater buffer. Fit trailer at the end - writeTrailer(buf, len); - len = len + TRAILER_SIZE; - out.write(buf, 0, len); - return; + try { + def.finish(); + while (!def.finished()) { + int len = def.deflate(buf, 0, buf.length); + if (def.finished() && len <= buf.length - TRAILER_SIZE) { + // last deflater buffer. Fit trailer at the end + writeTrailer(buf, len); + len = len + TRAILER_SIZE; + out.write(buf, 0, len); + return; + } + if (len > 0) + out.write(buf, 0, len); } - if (len > 0) - out.write(buf, 0, len); + // if we can't fit the trailer at the end of the last + // deflater buffer, we write it separately + byte[] trailer = new byte[TRAILER_SIZE]; + writeTrailer(trailer, 0); + out.write(trailer); + } catch (IOException e) { + if (usesDefaultDeflater) + def.end(); + throw e; } - // if we can't fit the trailer at the end of the last - // deflater buffer, we write it separately - byte[] trailer = new byte[TRAILER_SIZE]; - writeTrailer(trailer, 0); - out.write(trailer); } } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/zip/ZipOutputStream.java openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/zip/ZipOutputStream.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/java/util/zip/ZipOutputStream.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/java/util/zip/ZipOutputStream.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,11 +144,14 @@ * ZIP file comment is greater than 0xFFFF bytes */ public void setComment(String comment) { + byte[] bytes = null; if (comment != null) { - this.comment = zc.getBytes(comment); - if (this.comment.length > 0xffff) - throw new IllegalArgumentException("ZIP file comment too long."); + bytes = zc.getBytes(comment); + if (bytes.length > 0xffff) { + throw new IllegalArgumentException("ZIP file comment too long"); + } } + this.comment = bytes; } /** @@ -256,58 +259,64 @@ public void closeEntry() throws IOException { ensureOpen(); if (current != null) { - ZipEntry e = current.entry; - switch (e.method) { - case DEFLATED -> { - def.finish(); - while (!def.finished()) { - deflate(); - } - if ((e.flag & 8) == 0) { - // verify size, compressed size, and crc-32 settings - if (e.size != def.getBytesRead()) { - throw new ZipException( - "invalid entry size (expected " + e.size + - " but got " + def.getBytesRead() + " bytes)"); + try { + ZipEntry e = current.entry; + switch (e.method) { + case DEFLATED -> { + def.finish(); + while (!def.finished()) { + deflate(); + } + if ((e.flag & 8) == 0) { + // verify size, compressed size, and crc-32 settings + if (e.size != def.getBytesRead()) { + throw new ZipException( + "invalid entry size (expected " + e.size + + " but got " + def.getBytesRead() + " bytes)"); + } + if (e.csize != def.getBytesWritten()) { + throw new ZipException( + "invalid entry compressed size (expected " + + e.csize + " but got " + def.getBytesWritten() + " bytes)"); + } + if (e.crc != crc.getValue()) { + throw new ZipException( + "invalid entry CRC-32 (expected 0x" + + Long.toHexString(e.crc) + " but got 0x" + + Long.toHexString(crc.getValue()) + ")"); + } + } else { + e.size = def.getBytesRead(); + e.csize = def.getBytesWritten(); + e.crc = crc.getValue(); + writeEXT(e); + } + def.reset(); + written += e.csize; } - if (e.csize != def.getBytesWritten()) { - throw new ZipException( - "invalid entry compressed size (expected " + - e.csize + " but got " + def.getBytesWritten() + " bytes)"); + case STORED -> { + // we already know that both e.size and e.csize are the same + if (e.size != written - locoff) { + throw new ZipException( + "invalid entry size (expected " + e.size + + " but got " + (written - locoff) + " bytes)"); + } + if (e.crc != crc.getValue()) { + throw new ZipException( + "invalid entry crc-32 (expected 0x" + + Long.toHexString(e.crc) + " but got 0x" + + Long.toHexString(crc.getValue()) + ")"); + } } - if (e.crc != crc.getValue()) { - throw new ZipException( - "invalid entry CRC-32 (expected 0x" + - Long.toHexString(e.crc) + " but got 0x" + - Long.toHexString(crc.getValue()) + ")"); - } - } else { - e.size = def.getBytesRead(); - e.csize = def.getBytesWritten(); - e.crc = crc.getValue(); - writeEXT(e); + default -> throw new ZipException("invalid compression method"); } - def.reset(); - written += e.csize; - } - case STORED -> { - // we already know that both e.size and e.csize are the same - if (e.size != written - locoff) { - throw new ZipException( - "invalid entry size (expected " + e.size + - " but got " + (written - locoff) + " bytes)"); - } - if (e.crc != crc.getValue()) { - throw new ZipException( - "invalid entry crc-32 (expected 0x" + - Long.toHexString(e.crc) + " but got 0x" + - Long.toHexString(crc.getValue()) + ")"); - } - } - default -> throw new ZipException("invalid compression method"); + crc.reset(); + current = null; + } catch (IOException e) { + if (def.shouldFinish() && usesDefaultDeflater && !(e instanceof ZipException)) + def.end(); + throw e; } - crc.reset(); - current = null; } } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/jdk/internal/module/ModulePath.java openjdk-17-17.0.4+8/src/java.base/share/classes/jdk/internal/module/ModulePath.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/jdk/internal/module/ModulePath.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/jdk/internal/module/ModulePath.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -663,11 +663,12 @@ // -- exploded directories -- private Set explodedPackages(Path dir) { + String separator = dir.getFileSystem().getSeparator(); try { return Files.find(dir, Integer.MAX_VALUE, ((path, attrs) -> attrs.isRegularFile() && !isHidden(path))) .map(path -> dir.relativize(path)) - .map(this::toPackageName) + .map(path -> toPackageName(path, separator)) .flatMap(Optional::stream) .collect(Collectors.toSet()); } catch (IOException x) { @@ -738,7 +739,7 @@ * @throws InvalidModuleDescriptorException if the name is a class file in * the top-level directory (and it's not module-info.class) */ - private Optional toPackageName(Path file) { + private Optional toPackageName(Path file, String separator) { assert file.getRoot() == null; Path parent = file.getParent(); @@ -752,7 +753,7 @@ return Optional.empty(); } - String pn = parent.toString().replace(File.separatorChar, '.'); + String pn = parent.toString().replace(separator, "."); if (Checks.isPackageName(pn)) { return Optional.of(pn); } else { diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java openjdk-17-17.0.4+8/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java 2022-07-14 08:05:38.000000000 +0000 @@ -1186,10 +1186,10 @@ // For the exponential distribution, every overhang is convex. final double[] X = DoubleZigguratTables.exponentialX; final double[] Y = DoubleZigguratTables.exponentialY; - for (;; U1 = (rng.nextLong() >>> 1)) { + // At this point, the high-order bits of U1 have not been used yet, + // but we need the value in U1 to be positive. + for (U1 = (U1 >>> 1);; U1 = (rng.nextLong() >>> 1)) { long U2 = (rng.nextLong() >>> 1); - // Compute the actual x-coordinate of the randomly chosen point. - double x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1); // Does the point lie below the curve? long Udiff = U2 - U1; if (Udiff < 0) { @@ -1200,11 +1200,13 @@ U2 = U1; U1 -= Udiff; } + // Compute the actual x-coordinate of the randomly chosen point. + double x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1); if (Udiff >= DoubleZigguratTables.exponentialConvexMargin) { return x + extra; // The chosen point is way below the curve; accept it. } // Compute the actual y-coordinate of the randomly chosen point. - double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2); + double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2); // Now see how that y-coordinate compares to the curve if (y <= Math.exp(-x)) { return x + extra; // The chosen point is below the curve; accept it. @@ -1323,7 +1325,7 @@ continue; // The chosen point is way above the curve; reject it. } // Compute the actual y-coordinate of the randomly chosen point. - double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2); + double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2); // Now see how that y-coordinate compares to the curve if (y <= Math.exp(-0.5*x*x)) { break; // The chosen point is below the curve; accept it. @@ -1348,8 +1350,6 @@ } else if (j < DoubleZigguratTables.normalInflectionIndex) { // Convex overhang for (;; U1 = (rng.nextLong() >>> 1)) { long U2 = (rng.nextLong() >>> 1); - // Compute the actual x-coordinate of the randomly chosen point. - x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1); // Does the point lie below the curve? long Udiff = U2 - U1; if (Udiff < 0) { @@ -1360,11 +1360,13 @@ U2 = U1; U1 -= Udiff; } + // Compute the actual x-coordinate of the randomly chosen point. + x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1); if (Udiff >= DoubleZigguratTables.normalConvexMargin) { break; // The chosen point is way below the curve; accept it. } // Compute the actual y-coordinate of the randomly chosen point. - double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2); + double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2); // Now see how that y-coordinate compares to the curve if (y <= Math.exp(-0.5*x*x)) break; // The chosen point is below the curve; accept it. // Otherwise, we reject this sample and have to try again. @@ -1384,7 +1386,7 @@ continue; // The chosen point is way above the curve; reject it. } // Compute the actual y-coordinate of the randomly chosen point. - double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2); + double y = (Y[j] * 0x1.0p63) + ((Y[j-1] - Y[j]) * (double)U2); // Now see how that y-coordinate compares to the curve if (y <= Math.exp(-0.5*x*x)) { break; // The chosen point is below the curve; accept it. diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java openjdk-17-17.0.4+8/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * 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.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import jdk.internal.org.xml.sax.InputSource; @@ -42,7 +43,11 @@ public static final String FAULT = ""; protected static final int BUFFSIZE_READER = 512; + // Initial buffer (mBuff) size protected static final int BUFFSIZE_PARSER = 128; + // Max buffer size + private static final int MAX_ARRAY_SIZE = 1024 << 16; + /** * The end of stream character. */ @@ -525,6 +530,10 @@ mPh = PH_DTD; // DTD for (short st = 0; st >= 0;) { ch = getch(); + // report error if EOS is reached while parsing the DTD + if (ch == EOS) { + panic(FAULT); + } switch (st) { case 0: // read the document type name if (chtyp(ch) != ' ') { @@ -1664,6 +1673,10 @@ mBuffIdx = -1; for (short st = 0; st >= 0;) { ch = getch(); + // report error if EOS is reached while parsing the DTD + if (ch == EOS) { + panic(FAULT); + } switch (st) { case 0: // the first '[' of the CDATA open if (ch == '[') { @@ -1871,7 +1884,7 @@ } /** - * Resoves an entity. + * Resolves an entity. * * This method resolves built-in and character entity references. It is also * reports external entities to the application. @@ -2529,7 +2542,7 @@ } /** - * Reads a single or double quotted string in to the buffer. + * Reads a single or double quoted string into the buffer. * * This method resolves entities inside a string unless the parser parses * DTD. @@ -2664,7 +2677,7 @@ * @param ch The character to append to the buffer. * @param mode The normalization mode. */ - private void bappend(char ch, char mode) { + private void bappend(char ch, char mode) throws Exception { // This implements attribute value normalization as // described in the XML specification [#3.3.3]. switch (mode) { @@ -2714,16 +2727,9 @@ * * @param ch The character to append to the buffer. */ - private void bappend(char ch) { - try { - mBuff[++mBuffIdx] = ch; - } catch (Exception exp) { - // Double the buffer size - char buff[] = new char[mBuff.length << 1]; - System.arraycopy(mBuff, 0, buff, 0, mBuff.length); - mBuff = buff; - mBuff[mBuffIdx] = ch; - } + private void bappend(char ch) throws Exception { + ensureCapacity(++mBuffIdx); + mBuff[mBuffIdx] = ch; } /** @@ -2733,14 +2739,9 @@ * @param cidx The character buffer (mChars) start index. * @param bidx The parser buffer (mBuff) start index. */ - private void bcopy(int cidx, int bidx) { + private void bcopy(int cidx, int bidx) throws Exception { int length = mChIdx - cidx; - if ((bidx + length + 1) >= mBuff.length) { - // Expand the buffer - char buff[] = new char[mBuff.length + length]; - System.arraycopy(mBuff, 0, buff, 0, mBuff.length); - mBuff = buff; - } + ensureCapacity(bidx + length + 1); System.arraycopy(mChars, cidx, mBuff, bidx, length); mBuffIdx += length; } @@ -3327,7 +3328,7 @@ } /** - * Retrives the next character in the document. + * Retrieves the next character in the document. * * @return The next character in the document. */ @@ -3433,4 +3434,23 @@ return next; } + + private void ensureCapacity(int minCapacity) throws Exception { + if (mBuff == null) { + int newCapacity = minCapacity > BUFFSIZE_PARSER ? + minCapacity + BUFFSIZE_PARSER : BUFFSIZE_PARSER; + mBuff = new char[newCapacity]; + return; + } + + if (mBuff.length <= minCapacity) { + int size = mBuff.length << 1; + int newCapacity = size > minCapacity ? size : minCapacity + BUFFSIZE_PARSER; + if (newCapacity < 0 || newCapacity > MAX_ARRAY_SIZE) { + panic(FAULT); + } + + mBuff = Arrays.copyOf(mBuff, newCapacity); + } + } } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/util/IPAddressUtil.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/util/IPAddressUtil.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/util/IPAddressUtil.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/util/IPAddressUtil.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ package sun.net.util; -import java.io.IOException; +import sun.security.action.GetPropertyAction; + import java.io.UncheckedIOException; import java.net.Inet6Address; import java.net.InetAddress; @@ -33,6 +34,7 @@ import java.net.NetworkInterface; import java.net.SocketException; import java.net.URL; +import java.nio.CharBuffer; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; @@ -100,7 +102,7 @@ tmpValue = 0; newOctet = true; } else { - int digit = Character.digit(c, 10); + int digit = digit(c, 10); if (digit < 0) { return null; } @@ -125,6 +127,29 @@ return res; } + /** + * Validates if input string is a valid IPv4 address literal. + * If the "jdk.net.allowAmbiguousIPAddressLiterals" system property is set + * to {@code false}, or is not set then validation of the address string is performed as follows: + * If string can't be parsed by following IETF IPv4 address string literals + * formatting style rules (default one), but can be parsed by following BSD formatting + * style rules, the IPv4 address string content is treated as ambiguous and + * {@code IllegalArgumentException} is thrown. + * + * @param src input string + * @return bytes array if string is a valid IPv4 address string + * @throws IllegalArgumentException if "jdk.net.allowAmbiguousIPAddressLiterals" SP is set to + * "false" and IPv4 address string {@code "src"} is ambiguous + */ + public static byte[] validateNumericFormatV4(String src) { + byte[] parsedBytes = textToNumericFormatV4(src); + if (!ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE + && parsedBytes == null && isBsdParsableV4(src)) { + throw new IllegalArgumentException("Invalid IP address literal: " + src); + } + return parsedBytes; + } + /* * Convert IPv6 presentation level address to network order binary form. * credit: @@ -170,7 +195,7 @@ val = 0; while (i < srcb_length) { ch = srcb[i++]; - int chval = Character.digit(ch, 16); + int chval = digit(ch, 16); if (chval != -1) { val <<= 4; val |= chval; @@ -551,4 +576,245 @@ } return null; } + + /** + * Returns the numeric value of the character {@code ch} in the + * specified radix. + * + * @param ch the character to be converted. + * @param radix the radix. + * @return the numeric value represented by the character in the + * specified radix. + */ + public static int digit(char ch, int radix) { + if (ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE) { + return Character.digit(ch, radix); + } else { + return parseAsciiDigit(ch, radix); + } + } + + /** + * Try to parse String as IPv4 address literal by following + * BSD-style formatting rules. + * + * @param input input string + * @return {@code true} if input string is parsable as IPv4 address literal, + * {@code false} otherwise. + */ + public static boolean isBsdParsableV4(String input) { + char firstSymbol = input.charAt(0); + // Check if first digit is not a decimal digit + if (parseAsciiDigit(firstSymbol, DECIMAL) == -1) { + return false; + } + + // Last character is dot OR is not a supported digit: [0-9,A-F,a-f] + char lastSymbol = input.charAt(input.length() - 1); + if (lastSymbol == '.' || parseAsciiHexDigit(lastSymbol) == -1) { + return false; + } + + // Parse IP address fields + CharBuffer charBuffer = CharBuffer.wrap(input); + int fieldNumber = 0; + while (charBuffer.hasRemaining()) { + long fieldValue = -1L; + // Try to parse fields in all supported radixes + for (int radix : SUPPORTED_RADIXES) { + fieldValue = parseV4FieldBsd(radix, charBuffer, fieldNumber); + if (fieldValue >= 0) { + fieldNumber++; + break; + } else if (fieldValue == TERMINAL_PARSE_ERROR) { + return false; + } + } + // If field can't be parsed as one of supported radixes stop + // parsing + if (fieldValue < 0) { + return false; + } + } + return true; + } + + /** + * Method tries to parse IP address field that starts from {@linkplain CharBuffer#position() + * current position} of the provided character buffer. + *

    + * This method supports three {@code "radix"} values to decode field values in + * {@code "HEXADECIMAL (radix=16)"}, {@code "DECIMAL (radix=10)"} and + * {@code "OCTAL (radix=8)"} radixes. + *

    + * If {@code -1} value is returned the char buffer position is reset to the value + * it was before it was called. + *

    + * Method returns {@code -2} if formatting illegal for all supported {@code radix} + * values is observed, and there is no point in checking other radix values. + * That includes the following cases:

      + *
    • Two subsequent dots are observer + *
    • Number of dots more than 3 + *
    • Field value exceeds max allowed + *
    • Character is not a valid digit for the requested {@code radix} value, given + * that a field has the radix specific prefix + *
    + * + * @param radix digits encoding radix to use for parsing. Valid values: 8, 10, 16. + * @param buffer {@code CharBuffer} with position set to the field's fist character + * @param fieldNumber parsed field number + * @return {@code CANT_PARSE_IN_RADIX} if field can not be parsed in requested {@code radix}. + * {@code TERMINAL_PARSE_ERROR} if field can't be parsed and the whole parse process should be terminated. + * Parsed field value otherwise. + */ + private static long parseV4FieldBsd(int radix, CharBuffer buffer, int fieldNumber) { + int initialPos = buffer.position(); + long val = 0; + int digitsCount = 0; + if (!checkPrefix(buffer, radix)) { + val = CANT_PARSE_IN_RADIX; + } + boolean dotSeen = false; + while (buffer.hasRemaining() && val != CANT_PARSE_IN_RADIX && !dotSeen) { + char c = buffer.get(); + if (c == '.') { + dotSeen = true; + // Fail if 4 dots in IP address string. + // fieldNumber counter starts from 0, therefore 3 + if (fieldNumber == 3) { + // Terminal state, can stop parsing: too many fields + return TERMINAL_PARSE_ERROR; + } + // Check for literals with two dots, like '1.2..3', '1.2.3..' + if (digitsCount == 0) { + // Terminal state, can stop parsing: dot with no digits + return TERMINAL_PARSE_ERROR; + } + if (val > 255) { + // Terminal state, can stop parsing: too big value for an octet + return TERMINAL_PARSE_ERROR; + } + } else { + int dv = parseAsciiDigit(c, radix); + if (dv >= 0) { + digitsCount++; + val *= radix; + val += dv; + } else { + // Spotted digit can't be parsed in the requested 'radix'. + // The order in which radixes are checked - hex, octal, decimal: + // - if symbol is not a valid digit in hex radix - terminal + // - if symbol is not a valid digit in octal radix, and given + // that octal prefix was observed before - terminal + // - if symbol is not a valid digit in decimal radix - terminal + return TERMINAL_PARSE_ERROR; + } + } + } + if (val == CANT_PARSE_IN_RADIX) { + buffer.position(initialPos); + } else if (!dotSeen) { + // It is the last field - check its value + // This check will ensure that address strings with less + // than 4 fields, i.e. A, A.B and A.B.C address types + // contain value less then the allowed maximum for the last field. + long maxValue = (1L << ((4 - fieldNumber) * 8)) - 1; + if (val > maxValue) { + // Terminal state, can stop parsing: last field value exceeds its + // allowed value + return TERMINAL_PARSE_ERROR; + } + } + return val; + } + + // This method moves the position of the supplied CharBuffer by analysing the digit prefix + // symbols if any. + // The caller should reset the position when method returns false. + private static boolean checkPrefix(CharBuffer buffer, int radix) { + return switch (radix) { + case OCTAL -> isOctalFieldStart(buffer); + case DECIMAL -> isDecimalFieldStart(buffer); + case HEXADECIMAL -> isHexFieldStart(buffer); + default -> throw new AssertionError("Not supported radix"); + }; + } + + // This method always moves the position of the supplied CharBuffer + // removing the octal prefix symbols '0'. + // The caller should reset the position when method returns false. + private static boolean isOctalFieldStart(CharBuffer cb) { + // .0 is not treated as octal field + if (cb.remaining() < 2) { + return false; + } + + // Fetch two first characters + int position = cb.position(); + char first = cb.get(); + char second = cb.get(); + + // Return false if the first char is not octal prefix '0' or second is a + // field separator - parseV4FieldBsd will reset position to start of the field. + // '.0.' fields will be successfully parsed in decimal radix. + boolean isOctalPrefix = first == '0' && second != '.'; + + // If the prefix looks like octal - consume '0', otherwise 'false' is returned + // and caller will reset the buffer position. + if (isOctalPrefix) { + cb.position(position + 1); + } + return isOctalPrefix; + } + + // This method doesn't move the position of the supplied CharBuffer + private static boolean isDecimalFieldStart(CharBuffer cb) { + return cb.hasRemaining(); + } + + // This method always moves the position of the supplied CharBuffer + // removing the hexadecimal prefix symbols '0x'. + // The caller should reset the position when method returns false. + private static boolean isHexFieldStart(CharBuffer cb) { + if (cb.remaining() < 2) { + return false; + } + char first = cb.get(); + char second = cb.get(); + return first == '0' && (second == 'x' || second == 'X'); + } + + // Parse ASCII digit in given radix + private static int parseAsciiDigit(char c, int radix) { + assert radix == OCTAL || radix == DECIMAL || radix == HEXADECIMAL; + if (radix == HEXADECIMAL) { + return parseAsciiHexDigit(c); + } + int val = c - '0'; + return (val < 0 || val >= radix) ? -1 : val; + } + + // Parse ASCII digit in hexadecimal radix + private static int parseAsciiHexDigit(char digit) { + char c = Character.toLowerCase(digit); + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + return parseAsciiDigit(c, DECIMAL); + } + + // Supported radixes + private static final int HEXADECIMAL = 16; + private static final int DECIMAL = 10; + private static final int OCTAL = 8; + // Order in which field formats are exercised to parse one IP address textual field + private static final int[] SUPPORTED_RADIXES = new int[]{HEXADECIMAL, OCTAL, DECIMAL}; + + // BSD parser's return values + private final static long CANT_PARSE_IN_RADIX = -1L; + private final static long TERMINAL_PARSE_ERROR = -2L; + + private static final String ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP = "jdk.net.allowAmbiguousIPAddressLiterals"; + private static final boolean ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE = Boolean.valueOf( + GetPropertyAction.privilegedGetProperty(ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP, "false")); } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/www/http/HttpClient.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/www/http/HttpClient.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/www/http/HttpClient.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/www/http/HttpClient.java 2022-07-14 08:05:38.000000000 +0000 @@ -144,12 +144,27 @@ // Traffic capture tool, if configured. See HttpCapture class for info private HttpCapture capture = null; + /* "jdk.https.negotiate.cbt" property can be set to "always" (always sent), "never" (never sent) or + * "domain:a,c.d,*.e.f" (sent to host a, or c.d or to the domain e.f and any of its subdomains). This is + * a comma separated list of arbitrary length with no white-space allowed. + * If enabled (for a particular destination) then Negotiate/SPNEGO authentication requests will include + * a channel binding token for the destination server. The default behavior and setting for the + * property is "never" + */ + private static final String spnegoCBT; + private static final PlatformLogger logger = HttpURLConnection.getHttpLogger(); + private static void logFinest(String msg) { if (logger.isLoggable(PlatformLogger.Level.FINEST)) { logger.finest(msg); } } + private static void logError(String msg) { + if (logger.isLoggable(PlatformLogger.Level.SEVERE)) { + logger.severe(msg); + } + } protected volatile String authenticatorKey; @@ -165,6 +180,18 @@ return keepAliveTimeout; } + static String normalizeCBT(String s) { + if (s == null || s.equals("never")) { + return "never"; + } + if (s.equals("always") || s.startsWith("domain:")) { + return s; + } else { + logError("Unexpected value for \"jdk.https.negotiate.cbt\" system property"); + return "never"; + } + } + static { Properties props = GetPropertyAction.privilegedGetProperties(); String keepAlive = props.getProperty("http.keepAlive"); @@ -172,6 +199,9 @@ String cacheNTLM = props.getProperty("jdk.ntlm.cache"); String cacheSPNEGO = props.getProperty("jdk.spnego.cache"); + String s = props.getProperty("jdk.https.negotiate.cbt"); + spnegoCBT = normalizeCBT(s); + if (keepAlive != null) { keepAliveProp = Boolean.parseBoolean(keepAlive); } else { @@ -206,6 +236,10 @@ } + public String getSpnegoCBT() { + return spnegoCBT; + } + protected HttpClient() { } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/www/protocol/http/HttpCallerInfo.java 2022-07-14 08:05:38.000000000 +0000 @@ -29,6 +29,7 @@ import java.net.Authenticator.RequestorType; import java.net.InetAddress; import java.net.URL; +import java.security.cert.X509Certificate; /** * Used in HTTP/Negotiate, to feed HTTP request info into JGSS as a HttpCaller, @@ -51,6 +52,9 @@ public final InetAddress addr; public final RequestorType authType; public final Authenticator authenticator; + // Used to obtain server cert for SPNEGO CBT. + // May be null in which case CBT is not set + public final X509Certificate serverCert; /** * Create a schemed object based on an un-schemed one. @@ -65,13 +69,19 @@ this.authType = old.authType; this.scheme = scheme; this.authenticator = old.authenticator; + this.serverCert = old.serverCert; } /** * Constructor an un-schemed object for site access. */ public HttpCallerInfo(URL url, Authenticator a) { + this(url, null, a); + } + + public HttpCallerInfo(URL url, X509Certificate serverCert, Authenticator a) { this.url= url; + this.serverCert= serverCert; prompt = ""; host = url.getHost(); @@ -100,9 +110,14 @@ * Constructor an un-schemed object for proxy access. */ public HttpCallerInfo(URL url, String host, int port, Authenticator a) { + this(url, host, port, null, a); + } + + public HttpCallerInfo(URL url, String host, int port, X509Certificate serverCert, Authenticator a) { this.url= url; this.host = host; this.port = port; + this.serverCert = serverCert; prompt = ""; addr = null; protocol = url.getProtocol(); diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java 2022-07-14 08:05:38.000000000 +0000 @@ -1740,7 +1740,7 @@ AuthenticationHeader authhdr = new AuthenticationHeader ( "Proxy-Authenticate", responses, - new HttpCallerInfo(url, + getHttpCallerInfo(url, http.getProxyHostUsed(), http.getProxyPortUsed(), authenticator), @@ -1815,7 +1815,7 @@ srvHdr = new AuthenticationHeader ( "WWW-Authenticate", responses, - new HttpCallerInfo(url, authenticator), + getHttpCallerInfo(url, authenticator), dontUseNegotiate ); @@ -2211,7 +2211,7 @@ AuthenticationHeader authhdr = new AuthenticationHeader( "Proxy-Authenticate", responses, - new HttpCallerInfo(url, + getHttpCallerInfo(url, http.getProxyHostUsed(), http.getProxyPortUsed(), authenticator), @@ -2280,6 +2280,21 @@ responses.reset(); } + /** + * Overridden in https to also include the server certificate + */ + protected HttpCallerInfo getHttpCallerInfo(URL url, String proxy, int port, + Authenticator authenticator) { + return new HttpCallerInfo(url, proxy, port, authenticator); + } + + /** + * Overridden in https to also include the server certificate + */ + protected HttpCallerInfo getHttpCallerInfo(URL url, Authenticator authenticator) { + return new HttpCallerInfo(url, authenticator); + } + static String connectRequestURI(URL url) { String host = url.getHost(); int port = url.getPort(); diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,4 +1,4 @@ -/* +/** * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,10 +25,13 @@ package sun.net.www.protocol.https; +import java.net.Authenticator; import java.net.URL; import java.net.Proxy; import java.net.SecureCacheResponse; import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; import java.io.IOException; import java.util.List; import java.util.Optional; @@ -36,6 +39,7 @@ import javax.net.ssl.SSLPeerUnverifiedException; import sun.net.www.http.*; import sun.net.www.protocol.http.HttpURLConnection; +import sun.net.www.protocol.http.HttpCallerInfo; /** * HTTPS URL connection support. @@ -309,4 +313,72 @@ return ((HttpsClient)http).getSSLSession(); } + + /* + * If no SSL Session available or if the system config does not allow it + * don't use the extended caller info (the server cert). + * Otherwise return true to include the server cert + */ + private boolean useExtendedCallerInfo(URL url) { + HttpsClient https = (HttpsClient)http; + if (https.getSSLSession() == null) { + return false; + } + String prop = http.getSpnegoCBT(); + if (prop.equals("never")) { + return false; + } + String target = url.getHost(); + if (prop.startsWith("domain:")) { + String[] domains = prop.substring(7).split(","); + for (String domain : domains) { + if (target.equalsIgnoreCase(domain)) { + return true; + } + if (domain.startsWith("*.") && target.regionMatches( + true, target.length() - domain.length() + 1, domain, 1, domain.length() - 1)) { + return true; + } + } + return false; + } + return true; + } + + @Override + protected HttpCallerInfo getHttpCallerInfo(URL url, String proxy, int port, + Authenticator authenticator) + { + if (!useExtendedCallerInfo(url)) { + return super.getHttpCallerInfo(url, proxy, port, authenticator); + } + HttpsClient https = (HttpsClient)http; + try { + Certificate[] certs = https.getServerCertificates(); + if (certs[0] instanceof X509Certificate x509Cert) { + return new HttpCallerInfo(url, proxy, port, x509Cert, authenticator); + } + } catch (SSLPeerUnverifiedException e) { + // ignore + } + return super.getHttpCallerInfo(url, proxy, port, authenticator); + } + + @Override + protected HttpCallerInfo getHttpCallerInfo(URL url, Authenticator authenticator) + { + if (!useExtendedCallerInfo(url)) { + return super.getHttpCallerInfo(url, authenticator); + } + HttpsClient https = (HttpsClient)http; + try { + Certificate[] certs = https.getServerCertificates(); + if (certs[0] instanceof X509Certificate x509Cert) { + return new HttpCallerInfo(url, x509Cert, authenticator); + } + } catch (SSLPeerUnverifiedException e) { + // ignore + } + return super.getHttpCallerInfo(url, authenticator); + } } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java 2022-07-14 08:05:38.000000000 +0000 @@ -61,6 +61,11 @@ class PollingWatchService extends AbstractWatchService { + // Wait between polling thread creation and first poll (seconds) + private static final int POLLING_INIT_DELAY = 1; + // Default time between polls (seconds) + private static final int DEFAULT_POLLING_INTERVAL = 2; + // map of registrations private final Map map = new HashMap<>(); @@ -115,7 +120,7 @@ throw new IllegalArgumentException("No events to register"); // Extended modifiers may be used to specify the sensitivity level - int sensitivity = 10; + int sensitivity = DEFAULT_POLLING_INTERVAL; if (modifiers.length > 0) { for (WatchEvent.Modifier modifier: modifiers) { if (modifier == null) @@ -247,6 +252,7 @@ * directory and queue keys when entries are added, modified, or deleted. */ private class PollingWatchKey extends AbstractWatchKey { + private final Object fileKey; // current event set @@ -305,10 +311,10 @@ // update the events this.events = events; - // create the periodic task + // create the periodic task with initialDelay set to the specified constant Runnable thunk = new Runnable() { public void run() { poll(); }}; this.poller = scheduledExecutor - .scheduleAtFixedRate(thunk, period, period, TimeUnit.SECONDS); + .scheduleAtFixedRate(thunk, POLLING_INIT_DELAY, period, TimeUnit.SECONDS); } } diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/BitArray.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/BitArray.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/BitArray.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/BitArray.java 2022-07-14 08:05:38.000000000 +0000 @@ -63,22 +63,32 @@ repn = new byte[(length + BITS_PER_UNIT - 1)/BITS_PER_UNIT]; } - /** * Creates a BitArray of the specified size, initialized from the - * specified byte array. The most significant bit of {@code a[0]} gets - * index zero in the BitArray. The array a must be large enough - * to specify a value for every bit in the BitArray. In other words, - * {@code 8*a.length <= length}. + * specified byte array. The most significant bit of {@code a[0]} gets + * index zero in the BitArray. The array must be large enough to specify + * a value for every bit of the BitArray. i.e. {@code 8*a.length <= length}. */ public BitArray(int length, byte[] a) throws IllegalArgumentException { + this(length, a, 0); + } + + /** + * Creates a BitArray of the specified size, initialized from the + * specified byte array starting at the specified offset. The most + * significant bit of {@code a[ofs]} gets index zero in the BitArray. + * The array must be large enough to specify a value for every bit of + * the BitArray, i.e. {@code 8*(a.length - ofs) <= length}. + */ + public BitArray(int length, byte[] a, int ofs) + throws IllegalArgumentException { if (length < 0) { throw new IllegalArgumentException("Negative length for BitArray"); } - if (a.length * BITS_PER_UNIT < length) { - throw new IllegalArgumentException("Byte array too short to represent " + - "bit array of given length"); + if ((a.length - ofs) * BITS_PER_UNIT < length) { + throw new IllegalArgumentException + ("Byte array too short to represent " + length + "-bit array"); } this.length = length; @@ -93,7 +103,7 @@ 2. zero out extra bits in the last byte */ repn = new byte[repLength]; - System.arraycopy(a, 0, repn, 0, repLength); + System.arraycopy(a, ofs, repn, 0, repLength); if (repLength > 0) { repn[repLength - 1] &= bitMask; } @@ -270,7 +280,7 @@ public BitArray truncate() { for (int i=length-1; i>=0; i--) { if (get(i)) { - return new BitArray(i+1, Arrays.copyOf(repn, (i + BITS_PER_UNIT)/BITS_PER_UNIT)); + return new BitArray(i+1, repn, 0); } } return new BitArray(1); diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/ChannelBindingException.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/ChannelBindingException.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/ChannelBindingException.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/ChannelBindingException.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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.util; + +import java.security.GeneralSecurityException; + +/** + * Thrown by TlsChannelBinding if an error occurs + */ +public class ChannelBindingException extends GeneralSecurityException { + + @java.io.Serial + private static final long serialVersionUID = -5021387249782788460L; + + /** + * Constructs a ChannelBindingException with no detail message. A detail + * message is a String that describes this particular exception. + */ + public ChannelBindingException() { + super(); + } + + /** + * Constructs a ChannelBindingException with a detail message and + * specified cause. + */ + public ChannelBindingException(String msg, Exception e) { + super(msg, e); + } + + /** + * Constructs a ChannelBindingException with a detail message + */ + public ChannelBindingException(String msg) { + super(msg); + } +} diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/DerValue.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/DerValue.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/DerValue.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/DerValue.java 2022-07-14 08:05:38.000000000 +0000 @@ -689,6 +689,28 @@ }; } + // check the number of pad bits, validate the pad bits in the bytes + // if enforcing DER (i.e. allowBER == false), and return the number of + // bits of the resulting BitString + private static int checkPaddedBits(int numOfPadBits, byte[] data, + int start, int end, boolean allowBER) throws IOException { + // number of pad bits should be from 0(min) to 7(max). + if ((numOfPadBits < 0) || (numOfPadBits > 7)) { + throw new IOException("Invalid number of padding bits"); + } + int lenInBits = ((end - start) << 3) - numOfPadBits; + if (lenInBits < 0) { + throw new IOException("Not enough bytes in BitString"); + } + + // padding bits should be all zeros for DER + if (!allowBER && numOfPadBits != 0 && + (data[end - 1] & (0xff >>> (8 - numOfPadBits))) != 0) { + throw new IOException("Invalid value of padding bits"); + } + return lenInBits; + } + /** * Returns an ASN.1 BIT STRING value, with the tag assumed implicit * based on the parameter. The bit string must be byte-aligned. @@ -705,18 +727,17 @@ } if (end == start) { throw new IOException("Invalid encoding: zero length bit string"); + } + data.pos = data.end; // Compatibility. Reach end. + int numOfPadBits = buffer[start]; - if ((numOfPadBits < 0) || (numOfPadBits > 7)) { - throw new IOException("Invalid number of padding bits"); - } - // minus the first byte which indicates the number of padding bits + checkPaddedBits(numOfPadBits, buffer, start + 1, end, allowBER); byte[] retval = Arrays.copyOfRange(buffer, start + 1, end); - if (numOfPadBits != 0) { - // get rid of the padding bits - retval[end - start - 2] &= (0xff << numOfPadBits); + if (allowBER && numOfPadBits != 0) { + // fix the potential non-zero padding bits + retval[retval.length - 1] &= (0xff << numOfPadBits); } - data.pos = data.end; // Compatibility. Reach end. return retval; } @@ -739,16 +760,11 @@ throw new IOException("Invalid encoding: zero length bit string"); } data.pos = data.end; // Compatibility. Reach end. + int numOfPadBits = buffer[start]; - if ((numOfPadBits < 0) || (numOfPadBits > 7)) { - throw new IOException("Invalid number of padding bits"); - } - if (end == start + 1) { - return new BitArray(0); - } else { - return new BitArray(((end - start - 1) << 3) - numOfPadBits, - Arrays.copyOfRange(buffer, start + 1, end)); - } + int len = checkPaddedBits(numOfPadBits, buffer, start + 1, end, + allowBER); + return new BitArray(len, buffer, start + 1); } /** diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * */ public CodeSigner[] verify(Hashtable verifiedSigners, - Hashtable sigFileSigners) + Hashtable sigFileSigners, + Map> signersToAlgs) throws JarException { if (skip) { @@ -207,38 +208,60 @@ return signers; } - JarConstraintsParameters params = - getParams(verifiedSigners, sigFileSigners); - + CodeSigner[] entrySigners = sigFileSigners.get(name); + Map algsPermittedStatus = + algsPermittedStatusForSigners(signersToAlgs, entrySigners); + + // Flag that indicates if only disabled algorithms are used and jar + // entry should be treated as unsigned. + boolean disabledAlgs = true; + JarConstraintsParameters params = null; for (int i=0; i < digests.size(); i++) { MessageDigest digest = digests.get(i); - if (params != null) { - try { - params.setExtendedExceptionMsg(JarFile.MANIFEST_NAME, - name + " entry"); - DisabledAlgorithmConstraints.jarConstraints() - .permits(digest.getAlgorithm(), params); - } catch (GeneralSecurityException e) { - if (debug != null) { - debug.println("Digest algorithm is restricted: " + e); + String digestAlg = digest.getAlgorithm(); + + // Check if this algorithm is permitted, skip if false. + if (algsPermittedStatus != null) { + Boolean permitted = algsPermittedStatus.get(digestAlg); + if (permitted == null) { + if (params == null) { + params = new JarConstraintsParameters(entrySigners); + } + if (!checkConstraints(digestAlg, params)) { + algsPermittedStatus.put(digestAlg, Boolean.FALSE); + continue; + } else { + algsPermittedStatus.put(digestAlg, Boolean.TRUE); } - return null; + } else if (!permitted) { + continue; } } + + // A non-disabled algorithm was used. + disabledAlgs = false; + byte [] manHash = manifestHashes.get(i); byte [] theHash = digest.digest(); if (debug != null) { debug.println("Manifest Entry: " + - name + " digest=" + digest.getAlgorithm()); + name + " digest=" + digestAlg); debug.println(" manifest " + HexFormat.of().formatHex(manHash)); debug.println(" computed " + HexFormat.of().formatHex(theHash)); debug.println(); } - if (!MessageDigest.isEqual(theHash, manHash)) - throw new SecurityException(digest.getAlgorithm()+ + if (!MessageDigest.isEqual(theHash, manHash)) { + throw new SecurityException(digestAlg + " digest error for "+name); + } + } + + // If there were only disabled algorithms used, return null and jar + // entry will be treated as unsigned. + if (disabledAlgs) { + return null; } // take it out of sigFileSigners and put it in verifiedSigners... @@ -249,40 +272,36 @@ return signers; } - /** - * Get constraints parameters for JAR. The constraints should be - * checked against all code signers. Returns the parameters, - * or null if the signers for this entry have already been checked - * or there are no signers for this entry. - */ - private JarConstraintsParameters getParams( - Map verifiedSigners, - Map sigFileSigners) { - - // verifiedSigners is usually preloaded with the Manifest's signers. - // If verifiedSigners contains the Manifest, then it will have all of - // the signers of the JAR. But if it doesn't then we need to fallback - // and check verifiedSigners to see if the signers of this entry have - // been checked already. - if (verifiedSigners.containsKey(manifestFileName)) { - if (verifiedSigners.size() > 1) { - // this means we already checked it previously - return null; - } else { - return new JarConstraintsParameters( - verifiedSigners.get(manifestFileName)); + // Gets the algorithms permitted status for the signers of this entry. + private static Map algsPermittedStatusForSigners( + Map> signersToAlgs, + CodeSigner[] signers) { + if (signers != null) { + Map algs = signersToAlgs.get(signers); + // create new HashMap if absent + if (algs == null) { + algs = new HashMap<>(); + signersToAlgs.put(signers, algs); } - } else { + return algs; + } + return null; + } + + // Checks the algorithm constraints against the signers of this entry. + private boolean checkConstraints(String algorithm, + JarConstraintsParameters params) { + try { + params.setExtendedExceptionMsg(JarFile.MANIFEST_NAME, + name + " entry"); + DisabledAlgorithmConstraints.jarConstraints() + .permits(algorithm, params); + return true; + } catch (GeneralSecurityException e) { if (debug != null) { - debug.println(manifestFileName + " not present in verifiedSigners"); - } - CodeSigner[] signers = sigFileSigners.get(name); - if (signers == null || verifiedSigners.containsValue(signers)) { - return null; - } else { - return new JarConstraintsParameters(signers); + debug.println("Digest algorithm is restricted: " + e); } + return false; } } } - diff -Nru openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/TlsChannelBinding.java openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/TlsChannelBinding.java --- openjdk-17-17.0.3+7/src/java.base/share/classes/sun/security/util/TlsChannelBinding.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/classes/sun/security/util/TlsChannelBinding.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.util; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Hashtable; + +/** + * This class implements the Channel Binding for TLS as defined in + * + * Channel Bindings for TLS + * + * Format of the Channel Binding data is also defined in + * + * On the Use of Channel Bindings to Secure Channels + * section 2.1. + * + */ + +public class TlsChannelBinding { + + public enum TlsChannelBindingType { + + /** + * Channel binding on the basis of TLS Finished message. + * TLS_UNIQUE is defined by RFC 5929 but is not supported + * by the current LDAP stack. + */ + TLS_UNIQUE("tls-unique"), + + /** + * Channel binding on the basis of TLS server certificate. + */ + TLS_SERVER_END_POINT("tls-server-end-point"); + + public String getName() { + return name; + } + + private final String name; + TlsChannelBindingType(String name) { + this.name = name; + } + } + + /** + * Parse given value to see if it is a recognized and supported channel binding type + * + * @param cbType + * @return TLS Channel Binding type or null if given string is null + * @throws ChannelBindingException + */ + public static TlsChannelBindingType parseType(String cbType) throws ChannelBindingException { + if (cbType != null) { + if (cbType.equals(TlsChannelBindingType.TLS_SERVER_END_POINT.getName())) { + return TlsChannelBindingType.TLS_SERVER_END_POINT; + } else { + throw new ChannelBindingException("Illegal value for channel binding type: " + cbType); + } + } + return null; + } + + private final TlsChannelBindingType cbType; + private final byte[] cbData; + + /** + * Construct tls-server-end-point Channel Binding data + * @param serverCertificate + * @throws ChannelBindingException + */ + public static TlsChannelBinding create(X509Certificate serverCertificate) throws ChannelBindingException { + try { + final byte[] prefix = + TlsChannelBindingType.TLS_SERVER_END_POINT.getName().concat(":").getBytes(); + String hashAlg = serverCertificate.getSigAlgName(). + replace("SHA", "SHA-").toUpperCase(); + int ind = hashAlg.indexOf("WITH"); + if (ind > 0) { + hashAlg = hashAlg.substring(0, ind); + if (hashAlg.equals("MD5") || hashAlg.equals("SHA-1")) { + hashAlg = "SHA-256"; + } + } else { + hashAlg = "SHA-256"; + } + MessageDigest md = MessageDigest.getInstance(hashAlg); + byte[] hash = md.digest(serverCertificate.getEncoded()); + byte[] cbData = Arrays.copyOf(prefix, prefix.length + hash.length ); + System.arraycopy(hash, 0, cbData, prefix.length, hash.length); + return new TlsChannelBinding(TlsChannelBindingType.TLS_SERVER_END_POINT, cbData); + } catch (NoSuchAlgorithmException | CertificateEncodingException e) { + throw new ChannelBindingException("Cannot create TLS channel binding data", e); + } + } + + private TlsChannelBinding(TlsChannelBindingType cbType, byte[] cbData) { + this.cbType = cbType; + this.cbData = cbData; + } + + public TlsChannelBindingType getType() { + return cbType; + } + + public byte[] getData() { + return cbData; + } +} diff -Nru openjdk-17-17.0.3+7/src/java.base/share/legal/public_suffix.md openjdk-17-17.0.4+8/src/java.base/share/legal/public_suffix.md --- openjdk-17-17.0.3+7/src/java.base/share/legal/public_suffix.md 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/legal/public_suffix.md 2022-07-14 08:05:38.000000000 +0000 @@ -11,7 +11,7 @@ The Source Code of this file is available under the Mozilla Public License, v. 2.0 and is located at -https://raw.githubusercontent.com/publicsuffix/list/cbbba1d234670453df9c930dfbf510c0474d4301/public_suffix_list.dat. +https://raw.githubusercontent.com/publicsuffix/list/3c213aab32b3c014f171b1673d4ce9b5cd72bf1c/public_suffix_list.dat. If a copy of the MPL was not distributed with this file, you can obtain one at https://mozilla.org/MPL/2.0/. diff -Nru openjdk-17-17.0.3+7/src/java.base/share/man/java.1 openjdk-17-17.0.4+8/src/java.base/share/man/java.1 --- openjdk-17-17.0.3+7/src/java.base/share/man/java.1 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/share/man/java.1 2022-07-14 08:05:38.000000000 +0000 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. .\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. .\" .\" This code is free software; you can redistribute it and/or modify it @@ -1078,8 +1078,10 @@ .RS .PP \f[B]Note:\f[R] The \f[CB]\-Xshare:on\f[R] option is used for testing -purposes only and may cause intermittent failures due to the use of -address space layout randomization by the operation system. +purposes only. +It may cause the VM to unexpectedly exit during start\-up when the CDS +archive cannot be used (for example, when certain VM parameters are +changed, or when a different JDK is used). This option should not be used in production environments. .RE .TP @@ -5287,293 +5289,83 @@ don\[aq]t have the privilege to lock pages in memory. .SH APPLICATION CLASS DATA SHARING .PP -Application Class Data Sharing (AppCDS) extends class data sharing (CDS) -to enable application classes to be placed in a shared archive. +Application Class Data Sharing (AppCDS) stores classes used by your +applications in an archive file. +Since these classes are stored in a format that can be loaded very +quickly (compared to classes stored in a JAR file), AppCDS can improve +the start\-up time of your applications. +In addition, AppCDS can reduce the runtime memory footprint by sharing +parts of these classes across multiple processes. .PP -In addition to the core library classes, AppCDS supports \f[B]Class Data -Sharing\f[R] -[https://docs.oracle.com/en/java/javase/12/vm/class\-data\-sharing.html#GUID\-7EAA3411\-8CF0\-4D19\-BD05\-DF5E1780AA91] -from the following locations: -.IP \[bu] 2 -Platform classes from the runtime image -.IP \[bu] 2 -Application classes from the runtime image -.IP \[bu] 2 -Application classes from the class path -.IP \[bu] 2 -Application classes from the module path +Classes in the CDS archive are stored in an optimized format that\[aq]s +about 2 to 5 times larger than classes stored in JAR files or the JDK +runtime image. +Therefore, it\[aq]s a good idea to archive only those classes that are +actually used by your application. +These usually are just a small portion of all available classes. +For example, your application may use only a few APIs provided by a +large library. +.SS Using CDS Archives .PP -Archiving application classes provides better start up time at runtime. -When running multiple JVM processes, AppCDS also reduces the runtime -footprint with memory sharing for read\-only metadata. +By default, in most JDK distributions, unless \f[CB]\-Xshare:off\f[R] is +specified, the JVM starts up with a default CDS archive, which is +usually located in \f[CB]JAVA_HOME/lib/server/classes.jsa\f[R] (or +\f[CB]JAVA_HOME\\bin\\server\\classes.jsa\f[R] on Windows). +This archive contains about 1300 core library classes that are used by +most applications. .PP -CDS/AppCDS supports archiving classes from JAR files only. +To use CDS for the exact set of classes used by your application, you +can use the \f[CB]\-XX:SharedArchiveFile\f[R] option, which has the +general form: +.RS .PP -Prior to JDK 11, a non\-empty directory was reported as a fatal error in -the following conditions: -.IP \[bu] 2 -For base CDS, a non\-empty directory cannot exist in the -\f[CB]\-Xbootclasspath/a\f[R] path +\f[CB]\-XX:SharedArchiveFile=:\f[R] +.RE .IP \[bu] 2 -With \f[CB]\-XX:+UseAppCDS\f[R], a non\-empty directory could not exist in -the \f[CB]\-Xbootclasspath/a\f[R] path, class path, and module path. -.PP -In JDK 11 and later, \f[CB]\-XX:+UseAppCDS\f[R] is obsolete and the -behavior for a non\-empty directory is based on the class types in the -classlist. -A non\-empty directory is reported as a fatal error in the following -conditions: +The \f[CB]\f[R] overrides the default CDS archive. .IP \[bu] 2 -If application classes or platform classes are not loaded, dump time -only reports an error if a non\-empty directory exists in -\f[CB]\-Xbootclasspath/a\f[R] path +The \f[CB]\f[R] provides additional classes that can be +loaded on top of those in the \f[CB]\f[R]. .IP \[bu] 2 -If application classes or platform classes are loaded, dump time reports -an error for a non\-empty directory that exists in -\f[CB]\-Xbootclasspath/a\f[R] path, class path, or module path +On Windows, the above path delimiter \f[CB]:\f[R] should be replaced with +\f[CB];\f[R] .PP -In JDK 11 and later, using -\f[CB]\-XX:DumpLoadedClassList=\f[R]\f[I]class_list_file\f[R] results a -generated classlist with all classes (both system library classes and -application classes) included. -You no longer have to specify \f[CB]\-XX:+UseAppCDS\f[R] with -\f[CB]\-XX:DumpLoadedClassList\f[R] to produce a complete class list. +(The names "static" and "dyanmic" are used for historical reasons. +The only significance is that the "static" archive is loaded first and +the "dynamic" archive is loaded second). .PP -In JDK 11 and later, because \f[CB]UseAppCDS\f[R] is obsolete, -\f[CB]SharedArchiveFile\f[R] becomes a product flag by default. -Specifying \f[CB]+UnlockDiagnosticVMOptions\f[R] for -\f[CB]SharedArchiveFile\f[R] is no longer needed in any configuration. -.PP -Class Data Sharing (CDS)/AppCDS does not support archiving array classes -in a class list. -When an array in the class list is encountered, CDS dump time gives the -explicit error message: +The JVM can use up to two archives. +To use only a single \f[CB]\f[R], you can omit the +\f[CB]\f[R] portion: .RS .PP -\f[CB]Preload\ Warning:\ Cannot\ find\f[R] \f[I]array_name\f[R] +\f[CB]\-XX:SharedArchiveFile=\f[R] .RE .PP -Although an array in the class list is not allowed, some array classes -can still be created at CDS/AppCDS dump time. -Those arrays are created during the execution of the Java code used by -the Java class loaders (\f[CB]PlatformClassLoader\f[R] and the system -class loader) to load classes at dump time. -The created arrays are archived with the rest of the loaded classes. -.SS Extending Class Data Sharing to Support the Module Path -.PP -In JDK 11, Class Data Sharing (CDS) has been improved to support -archiving classes from the module path. -.IP \[bu] 2 -To create a CDS archive using the \f[CB]\-\-module\-path\f[R] VM option, -use the following command line syntax: -.RS 2 +For convenience, the \f[CB]\f[R] records the location of +the \f[CB]\f[R]. +Therefore, you can omit the \f[CB]\f[R] by saying only: .RS .PP -\f[CB]java\ \-Xshare:dump\ \-XX:SharedClassListFile=\f[R]\f[I]class_list_file\f[R] -\f[CB]\-XX:SharedArchiveFile=\f[R]\f[I]shared_archive_file\f[R] -\f[CB]\-\-module\-path=\f[R]\f[I]path_to_modular_jar\f[R] \f[CB]\-m\f[R] -\f[I]module_name\f[R] -.RE -.RE -.IP \[bu] 2 -To run with a CDS archive using the \f[CB]\-\-module\-path\f[R] VM option, -use the following the command line syntax: -.RS 2 -.RS -.PP -\f[CB]java\ \-XX:SharedArchiveFile=\f[R]\f[I]shared_archive_file\f[R] -\f[CB]\-\-module\-path=\f[R]\f[I]path_to_modular_jar\f[R] \f[CB]\-m\f[R] -\f[I]module_name\f[R] -.RE +\f[CB]\-XX:SharedArchiveFile=\f[R] .RE +.SS Creating CDS Archives .PP -The following table describes how the VM options related to module paths -can be used along with the \f[CB]\-Xshare\f[R] option. -.PP -.TS -tab(@); -l l l. -T{ -Option -T}@T{ -\-Xshare:dump -T}@T{ -\-Xshare:{on,auto} -T} -_ -T{ -\f[CB]\-\-module\-path\f[R][1] \f[I]mp\f[R] -T}@T{ -Allowed -T}@T{ -Allowed[2] -T} -T{ -\f[CB]\-\-module\f[R] -T}@T{ -Allowed -T}@T{ -Allowed -T} -T{ -\f[CB]\-\-add\-module\f[R] -T}@T{ -Allowed -T}@T{ -Allowed -T} -T{ -\f[CB]\-\-upgrade\-module\-path\f[R][3] -T}@T{ -Disallowed (exits if specified) -T}@T{ -Allowed (disables CDS) -T} -T{ -\f[CB]\-\-patch\-module\f[R][4] -T}@T{ -Disallowed (exits if specified) -T}@T{ -Allowed (disables CDS) -T} -T{ -\f[CB]\-\-limit\-modules\f[R][5] -T}@T{ -Disallowed (exits if specified) -T}@T{ -Allowed (disables CDS) -T} -.TE -.PP -[1] Although there are two ways of specifying a module in a -\f[CB]\-\-module\-path\f[R], that is, modular JAR or exploded module, only -modular JARs are supported. -.PP -[2] Different \f[I]mp\f[R] can be specified during dump time versus run -time. -If an archived class K was loaded from \f[CB]mp1.jar\f[R] at dump time, -but changes in \f[I]mp\f[R] cause it to be available from a different -\f[CB]mp2.jar\f[R] at run time, then the archived version of K will be -disregarded at run time; K will be loaded dynamically. -.PP -[3] Currently, only two system modules are upgradeable -(\f[CB]java.compiler\f[R] and \f[CB]jdk.internal.vm.compiler\f[R]). -However, these modules are seldom upgraded in production software. -.PP -[4] As documented in JEP 261, using \f[CB]\-\-patch\-module\f[R] is -strongly discouraged for production use. -.PP -[5] \f[CB]\-\-limit\-modules\f[R] is intended for testing purposes. -It is seldom used in production software. -.PP -If \f[CB]\-\-upgrade\-module\-path\f[R], \f[CB]\-\-patch\-module\f[R], or -\f[CB]\-\-limit\-modules\f[R] is specified at dump time, an error will be -printed and the JVM will exit. -For example, if the \f[CB]\-\-limit\-modules\f[R] option is specified at -dump time, the user will see the following error: -.IP -.nf -\f[CB] -Error\ occurred\ during\ initialization\ of\ VM -Cannot\ use\ the\ following\ option\ when\ dumping\ the\ shared\ archive:\ \-\-limit\-modules -\f[R] -.fi -.PP -If \f[CB]\-\-upgrade\-module\-path\f[R], \f[CB]\-\-patch\-module\f[R], or -\f[CB]\-\-limit\-modules\f[R] is specified at run time, a warning message -will be printed indicating that CDS is disabled. -For example, if the \f[CB]\-\-limit\-modules\f[R] options is specified at -run time, the user will see the following warning: -.IP -.nf -\f[CB] -Java\ HotSpot(TM)\ 64\-Bit\ Server\ VM\ warning:\ CDS\ is\ disabled\ when\ the\ \-\-limit\-modules\ option\ is\ specified. -\f[R] -.fi -.PP -Several other noteworthy things include: +CDS archives can be created with several methods: .IP \[bu] 2 -Any valid combinations of \f[CB]\-cp\f[R] and \f[CB]\-\-module\-path\f[R] -are supported. +\f[CB]\-Xshare:dump\f[R] .IP \[bu] 2 -A non\-empty directory in the module path causes a fatal error. -The user will see the following error messages: -.RS 2 -.IP -.nf -\f[CB] -Error:\ non\-empty\ directory\ \ Hint:\ enable\ \-Xlog:class+path=info\ to\ diagnose\ the\ failure\ Error\ occurred\ during\ initialization\ of\ VM\ Cannot\ have\ non\-empty\ directory\ in\ paths -\f[R] -.fi -.RE +\f[CB]\-XX:ArchiveClassesAtExit\f[R] .IP \[bu] 2 -Unlike the class path, there\[aq]s no restriction that the module path -at dump time must be equal to or be a prefix of the module path at run -time. -.IP \[bu] 2 -The archive is invalidated if an existing JAR in the module path is -updated after archive generation. -.IP \[bu] 2 -Removing a JAR from the module path does not invalidate the shared -archive. -Archived classes from the removed JAR are not used at runtime. -.SS Dynamic CDS archive -.PP -Dynamic CDS archive extends AppCDS to allow archiving of classes when a -Java application exits. -It improves the usability of AppCDS by eliminating the trial run step -for creating a class list for each application. -The archived classes include all loaded application classes and library -classes that are not present in the default CDS archive which is -included in the JDK. -.PP -A base archive is required when creating a dynamic archive. -If the base archive is not specified, the default CDS archive is used as -the base archive. -.PP -To create a dynamic CDS archive with the default CDS archive as the base -archive, just add the -\f[CB]\-XX:ArchiveClassesAtExit=\f[R] option to the -command line for running the Java application. +\f[CB]jcmd\ VM.cds\f[R] .PP -If the default CDS archive does not exist, the VM will exit with the -following error: -.IP -.nf -\f[CB] -ArchiveClassesAtExit\ not\ supported\ when\ base\ CDS\ archive\ is\ not\ loaded -\f[R] -.fi +One common operation in all these methods is a "trial run", where you +run the application once to determine the classes that should be stored +in the archive. +.SS Creating a Static CDS Archive File with \-Xshare:dump .PP -To run the Java application using a dynamic CDS archive, just add the -\f[CB]\-XX:SharedArchiveFile=\f[R] option to the command -line for running the Java application. -.PP -The base archive is not required to be specified in the command line. -The base archive information, including its name and full path, will be -retrieved from the dynamic archive header. -Note that the user could also use the \f[CB]\-XX:SharedArchiveFile\f[R] -option for specifying a regular AppCDS archive. -Therefore, the specified archive in the \f[CB]\-XX:SharedArchiveFile\f[R] -option could be either a regular or dynamic archive. -During VM start up the specified archive header will be read. -If \f[CB]\-XX:SharedArchiveFile\f[R] refers to a regular archive, then the -behavior will be unchanged. -If \f[CB]\-XX:SharedArchiveFile\f[R] refers to a dynamic archive, the VM -will retrieve the base archive location from the dynamic archive. -If the dynamic archive was created with the default CDS archive, then -the current default CDS archive will be used, and will be found relative -to the current run time environment. -.PP -Please refer to \f[B]JDK\-8221706\f[R] -[https://bugs.openjdk.java.net/browse/JDK\-8221706] for details on error -checking during dynamic CDS archive dump time and run time. -.SS Creating a Shared Archive File and Using It to Run an Application -.SS AppCDS archive -.PP -The following steps create a shared archive file that contains all the -classes used by the \f[CB]test.Hello\f[R] application. -The last step runs the application with the shared archive file. +The following steps create a static CDS archive file that contains all +the classes used by the \f[CB]test.Hello\f[R] application. .IP "1." 3 Create a list of all classes used by the \f[CB]test.Hello\f[R] application. @@ -5585,23 +5377,20 @@ \f[CB]java\ \-Xshare:off\ \-XX:DumpLoadedClassList=hello.classlist\ \-cp\ hello.jar\ test.Hello\f[R] .RE .PP -Note that the classpath specified by the \f[CB]\-cp\f[R] parameter must -contain only JAR files. +The classpath specified by the \f[CB]\-cp\f[R] parameter must contain only +JAR files. .RE .IP "2." 3 -Create a shared archive, named \f[CB]hello.jsa\f[R], that contains all the +Create a static archive, named \f[CB]hello.jsa\f[R], that contains all the classes in \f[CB]hello.classlist\f[R]: .RS 4 .RS .PP \f[CB]java\ \-Xshare:dump\ \-XX:SharedArchiveFile=hello.jsa\ \-XX:SharedClassListFile=hello.classlist\ \-cp\ hello.jar\f[R] .RE -.PP -Note that the classpath used at archive creation time must be the same -as (or a prefix of) the classpath used at run time. .RE .IP "3." 3 -Run the application \f[CB]test.Hello\f[R] with the shared archive +Run the application \f[CB]test.Hello\f[R] with the archive \f[CB]hello.jsa\f[R]: .RS 4 .RS @@ -5615,23 +5404,27 @@ .RS 4 .RS .PP -\f[CB]java\ \-XX:SharedArchiveFile=hello.jsa\ \-cp\ hello.jar\ \-verbose:class\ test.Hello\f[R] +\f[CB]java\ \-XX:SharedArchiveFile=hello.jsa\ \-cp\ hello.jar\ \-Xlog:class+load\ test.Hello\f[R] .RE .PP The output of this command should contain the following text: -.IP -.nf -\f[CB] -Loaded\ test.Hello\ from\ shared\ objects\ file\ by\ sun/misc/Launcher$AppClassLoader -\f[R] -.fi +.RS +.PP +\f[CB][info][class,load]\ test.Hello\ source:\ shared\ objects\ file\f[R] .RE -.SS Dynamic CDS archive +.RE +.SS Creating a Dynamic CDS Archive File with \-XX:SharedArchiveFile +.PP +Advantages of dynamic CDS archives are: +.IP \[bu] 2 +They usually use less disk space, since they don\[aq]t need to store the +classes that are already in the static archive. +.IP \[bu] 2 +They are created with one fewer step than the comparable static archive. .PP The following steps create a dynamic CDS archive file that contains the -classes used by the \f[CB]test.Hello\f[R] application and are not included -in the default CDS archive. -The second step runs the application with the dynamic CDS archive. +classes that are used by the \f[CB]test.Hello\f[R] application, excluding +those that are already in the default CDS archive. .IP "1." 3 Create a dynamic CDS archive, named \f[CB]hello.jsa\f[R], that contains all the classes in \f[CB]hello.jar\f[R] loaded by the application @@ -5641,9 +5434,6 @@ .PP \f[CB]java\ \-XX:ArchiveClassesAtExit=hello.jsa\ \-cp\ hello.jar\ Hello\f[R] .RE -.PP -Note that the classpath used at archive creation time must be the same -as (or a prefix of) the classpath used at run time. .RE .IP "2." 3 Run the application \f[CB]test.Hello\f[R] with the shared archive @@ -5659,218 +5449,87 @@ the \f[CB]test.Hello\f[R] application is using the class contained in the \f[CB]hello.jsa\f[R] shared archive. .PP -To automate the above steps 1 and 2, one can write a script such as the -following: -.IP -.nf -\f[CB] -\ \ \ \ ARCHIVE=hello.jsa -\ \ \ \ if\ test\ \-f\ $ARCHIVE;\ then -\ \ \ \ \ \ \ \ FLAG="\-XX:SharedArchiveFile=$ARCHIVE" -\ \ \ \ else -\ \ \ \ \ \ \ \ FLAG="\-XX:ArchiveClassesAtExit=$ARCHIVE" -\ \ \ \ fi -\ \ \ \ $JAVA_HOME/bin/java\ \-cp\ hello.jar\ $FLAG\ test.Hello -\f[R] -.fi -.PP -Like an AppCDS archive, the archive needs to be re\-generated if the -Java version has changed. -The above script could be adjusted to account for the Java version as -follows: -.IP -.nf -\f[CB] -\ \ \ \ ARCHIVE=hello.jsa -\ \ \ \ VERSION=foo.version -\ \ \ \ if\ test\ \-f\ $ARCHIVE\ \-a\ \-f\ $VERSION\ &&\ cmp\ \-s\ $VERSION\ $JAVA_HOME/release;\ then -\ \ \ \ \ \ \ \ FLAG="\-XX:SharedArchiveFile=$ARCHIVE" -\ \ \ \ else -\ \ \ \ \ \ \ \ FLAG="\-XX:ArchiveClassesAtExit=$ARCHIVE" -\ \ \ \ \ \ \ \ cp\ \-f\ $JAVA_HOME/release\ $VERSION -\ \ \ \ fi -\ \ \ \ $JAVA_HOME/bin/java\ \-cp\ hello.jar\ $FLAG\ test.Hello -\f[R] -.fi -.PP -Currently, we don\[aq]t support concurrent dumping operations to the -same CDS archive. -Care should be taken to avoid multiple writers to the same CDS archive. -.PP -The user could also create a dynamic CDS archive with a specific base -archive, e.g. -named as \f[CB]base.jsa\f[R] as follows: +It\[aq]s also possible to create a dynamic CDS archive with a +non\-default static CDS archive. +E.g., .RS .PP \f[CB]java\ \-XX:SharedArchiveFile=base.jsa\ \-XX:ArchiveClassesAtExit=hello.jsa\ \-cp\ hello.jar\ Hello\f[R] .RE .PP -To run the application using the dynamic CDS archive \f[CB]hello.jsa\f[R] -and a specific base CDS archive \f[CB]base.jsa\f[R]: +To run the application using this dynamic CDS archive: .RS .PP \f[CB]java\ \-XX:SharedArchiveFile=base.jsa:hello.jsa\ \-cp\ hello.jar\ Hello\f[R] .RE .PP -Note that on Windows, the above path delimiter \f[CB]:\f[R] should be -replaced with \f[CB];\f[R]. +(On Windows, the above path delimiter \f[CB]:\f[R] should be replaced with +\f[CB];\f[R]) .PP -The above command for specifying a base archive is useful if the base -archive used for creating the dynamic archive has been moved. -Normally, just specifying the dynamic archive should be sufficient since -the base archive info can be retrieved from the dynamic archive header. -.SS Sharing a Shared Archive Across Multiple Application Processes -.PP -You can share the same archive file across multiple applications -processes. -This reduces memory usage because the archive is memory\-mapped into the -address space of the processes. -The operating system automatically shares the read\-only pages across -these processes. -.PP -The following steps demonstrate how to create a common archive that can -be shared by different applications. -Classes from \f[CB]common.jar\f[R], \f[CB]hello.jar\f[R] and \f[CB]hi.jar\f[R] -are archived in the \f[CB]common.jsa\f[R] because they are all in the -classpath during the archiving step (step 3). -.PP -To include classes from \f[CB]hello.jar\f[R] and \f[CB]hi.jar\f[R], the -\f[CB]\&.jar\f[R] files must be added to the classpath specified by the -\f[CB]\-cp\f[R] parameter. -.IP "1." 3 -Create a list of all classes used by the \f[CB]Hello\f[R] application and -another list for the \f[CB]Hi\f[R] application: -.RS 4 +As mention above, the name of the static archive can be skipped: .RS .PP -\f[CB]java\ \-XX:DumpLoadedClassList=hello.classlist\ \-cp\ common.jar:hello.jar\ Hello\f[R] +\f[CB]java\ \-XX:SharedArchiveFile=hello.jsa\ \-cp\ hello.jar\ Hello\f[R] .RE -.RS +.SS Creating CDS Archive Files with jcmd .PP -\f[CB]java\ \-XX:DumpLoadedClassList=hi.classlist\ \-cp\ common.jar:hi.jar\ Hi\f[R] -.RE -.RE -.IP "2." 3 -Create a single list of classes used by all the applications that will -share the shared archive file. -.RS 4 +The previous two sections require you to modify the application\[aq]s +start\-up script in order to create a CDS archive. +Sometimes this could be difficult, for example, if the application\[aq]s +class path is set up by complex routines. .PP -\f[B]Linux and macOS\f[R] The following commands combine the files -\f[CB]hello.classlist\f[R] and \f[CB]hi.classlist\f[R] into one file, -\f[CB]common.classlist\f[R]: +The \f[CB]jcmd\ VM.cds\f[R] command provides a less intrusive way for +creating a CDS archive by connecting to a running JVM process. +You can create either a static: .RS .PP -\f[CB]cat\ hello.classlist\ hi.classlist\ >\ common.classlist\f[R] +\f[CB]jcmd\ \ VM.cds\ static_dump\ my_static_archive.jsa\f[R] .RE .PP -\f[B]Windows\f[R] The following commands combine the files -\f[CB]hello.classlist\f[R] and \f[CB]hi.classlist\f[R] into one file, -\f[CB]common.classlist\f[R]: +or a dynamic archive: .RS .PP -\f[CB]type\ hello.classlist\ hi.classlist\ >\ common.classlist\f[R] -.RE +\f[CB]jcmd\ \ VM.cds\ dynamic_dump\ my_dynamic_archive.jsa\f[R] .RE -.IP "3." 3 -Create a shared archive named \f[CB]common.jsa\f[R] that contains all the -classes in \f[CB]common.classlist\f[R]: -.RS 4 -.RS -.PP -\f[CB]java\ \-Xshare:dump\ \-XX:SharedArchiveFile=common.jsa\ \-XX:SharedClassListFile=common.classlist\ \-cp\ common.jar:hello.jar:hi.jar\f[R] -.RE -.PP -The classpath parameter used is the common class path prefix shared by -the \f[CB]Hello\f[R] and \f[CB]Hi\f[R] applications. -.RE -.IP "4." 3 -Run the \f[CB]Hello\f[R] and \f[CB]Hi\f[R] applications with the same shared -archive: -.RS 4 -.RS .PP -\f[CB]java\ \-XX:SharedArchiveFile=common.jsa\ \-cp\ common.jar:hello.jar:hi.jar\ Hello\f[R] -.RE +To use the resulting archive file in a subsequent run of the application +without modifying the application\[aq]s start\-up script, you can use +the following technique: .RS .PP -\f[CB]java\ \-XX:SharedArchiveFile=common.jsa\ \-cp\ common.jar:hello.jar:hi.jar\ Hi\f[R] -.RE +\f[CB]env\ JAVA_TOOL_OPTIONS=\-XX:SharedArchiveFile=my_static_archive.jsa\ bash\ app_start.sh\f[R] .RE -.SS Specifying Additional Shared Data Added to an Archive File .PP -The \f[CB]SharedArchiveConfigFile\f[R] option is used to specify -additional shared data to add to the archive file. +Note: to use \f[CB]jcmd\ \ VM.cds\ dynamic_dump\f[R], the JVM process +identified by \f[CB]\f[R] must be started with +\f[CB]\-XX:+RecordDynamicDumpInfo\f[R], which can also be passed to the +application start\-up script with the same technique: .RS .PP -\f[CB]\-XX:SharedArchiveConfigFile=\f[R]\f[I]shared_config_file\f[R] +\f[CB]env\ JAVA_TOOL_OPTIONS=\-XX:+RecordDynamicDumpInfo\ bash\ app_start.sh\f[R] .RE -.PP -JDK 9 and later supports adding both symbols and string objects to an -archive for memory sharing when you have multiple JVM processes running -on the same host. -An example of this is having multiple JVM processes that use the same -set of Java EE classes. -When these common classes are loaded and used, new symbols and strings -may be created and added to the JVM\[aq]s internal "symbol" and "string" -tables. -At runtime, the symbols or string objects mapped from the archive file -can be shared across multiple JVM processes, resulting in a reduction of -overall memory usage. -In addition, archiving strings also provides added performance benefits -in both startup time and runtime execution. -.PP -In JDK 10 and later, CONSTANT_String entries in archived classes are -resolved to interned String objects at dump time, and all interned -String objects are archived. -However, even though all CONSTANT_String literals in all archived -classes are resolved, it might still beneficial to add additional -strings that are not string literals in class files, but are likely to -be used by your application at run time. -.PP -Symbol data should be generated by the \f[CB]jcmd\f[R] tool attaching to a -running JVM process. -See \f[B]jcmd\f[R]. -.PP -The following is an example of the symbol dumping command in -\f[CB]jcmd\f[R]: -.RS -.PP -\f[CB]jcmd\f[R] \f[I]pid\f[R] \f[CB]VM.symboltable\ \-verbose\f[R] -.RE -.RS -.PP -\f[B]Note:\f[R] The first line (process ID) and the second line -(\f[CB]\@VERSION\ ...\f[R]) of this \f[CB]jcmd\f[R] output should be -excluded from the configuration file. -.RE -.SS Example of a Configuration File -.PP -The following is an example of a configuration file: -.IP -.nf -\f[CB] -VERSION:\ 1.0 -\@SECTION:\ Symbol -10\ \-1:\ linkMethod -\f[R] -.fi -.PP -In the configuration file example, the \f[CB]\@SECTION:\ Symbol\f[R] entry -uses the following format: -.RS -.PP -\f[I]length\f[R] \f[I]refcount\f[R]\f[CB]:\f[R] \f[I]symbol\f[R] -.RE -.PP -The \f[I]refcount\f[R] for a shared symbol is always \f[CB]\-1\f[R]. -.PP -\f[CB]\@SECTION\f[R] specifies the type of the section that follows it. -All data within the section must be the same type that\[aq]s specified -by \f[CB]\@SECTION\f[R]. -Different types of data can\[aq]t be mixed. -Multiple separated data sections for the same type specified by -different \f[CB]\@SECTION\f[R] are allowed within one -\f[CB]shared_config_file\f[R] . +.SS Restrictions on Class Path and Module Path +.IP \[bu] 2 +Neither the class path (\f[CB]\-classpath\f[R] and +\f[CB]\-Xbootclasspath/a\f[R]) nor the module path +(\f[CB]\-\-module\-path\f[R]) can contain non\-empty directories. +.IP \[bu] 2 +Only modular JAR files are supported in \f[CB]\-\-module\-path\f[R]. +Exploded modules are not supported. +.IP \[bu] 2 +The class path used at archive creation time must be the same as (or a +prefix of) the class path used at run time. +(There\[aq]s no such requirement for the module path.) +.IP \[bu] 2 +The CDS archive cannot be loaded if any JAR files in the class path or +module path are modified after the archive is generated. +.IP \[bu] 2 +If any of the VM options \f[CB]\-\-upgrade\-module\-path\f[R], +\f[CB]\-\-patch\-module\f[R] or \f[CB]\-\-limit\-modules\f[R] are specified, +CDS is disabled. +This means that the JVM will execute without loading any CDS archives. +In addition, if you try to create a CDS archive with any of these 3 +options specified, the JVM will report an error. .SH PERFORMANCE TUNING EXAMPLES .PP You can use the Java advanced runtime options to optimize the diff -Nru openjdk-17-17.0.3+7/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c openjdk-17-17.0.4+8/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c --- openjdk-17-17.0.3+7/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c 2022-07-14 08:05:38.000000000 +0000 @@ -50,20 +50,28 @@ jint fd = fdval(env, fdo); int rv; +#if defined(__APPLE__) + // On macOS systems we use disconnectx + rv = disconnectx(fd, SAE_ASSOCID_ANY, SAE_CONNID_ANY); +#else SOCKETADDRESS sa; + memset(&sa, 0, sizeof(sa)); + #if defined(_ALLBSD_SOURCE) + sa.sa.sa_family = isIPv6 ? AF_INET6 : AF_INET; + #else + sa.sa.sa_family = AF_UNSPEC; + #endif socklen_t len = isIPv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); - - memset(&sa, 0, sizeof(sa)); -#if defined(_ALLBSD_SOURCE) - sa.sa.sa_family = isIPv6 ? AF_INET6 : AF_INET; -#else - sa.sa.sa_family = AF_UNSPEC; -#endif - rv = connect(fd, &sa.sa, len); +#endif -#if defined(_ALLBSD_SOURCE) +#if defined(_ALLBSD_SOURCE) && !defined(__APPLE__) + // On _ALLBSD_SOURCE except __APPLE__ we consider EADDRNOTAVAIL + // error to be OK and ignore it. __APPLE__ systems are excluded + // in this check since for __APPLE__ systems, unlike other BSD systems, + // we issue a "disconnectx" call (a few lines above), + // which isn't expected to return this error code. if (rv < 0 && errno == EADDRNOTAVAIL) rv = errno = 0; #elif defined(_AIX) diff -Nru openjdk-17-17.0.3+7/src/java.base/windows/classes/java/io/WinNTFileSystem.java openjdk-17-17.0.4+8/src/java.base/windows/classes/java/io/WinNTFileSystem.java --- openjdk-17-17.0.3+7/src/java.base/windows/classes/java/io/WinNTFileSystem.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/windows/classes/java/io/WinNTFileSystem.java 2022-07-14 08:05:38.000000000 +0000 @@ -48,16 +48,15 @@ // Whether to enable alternative data streams (ADS) by suppressing // checking the path for invalid characters, in particular ":". - // ADS support will be enabled if and only if the property is set and - // is the empty string or is equal, ignoring case, to the string "true". - // By default ADS support is disabled. + // By default, ADS support is enabled and will be disabled if and + // only if the property is set, ignoring case, to the string "false". private static final boolean ENABLE_ADS; static { String enableADS = GetPropertyAction.privilegedGetProperty("jdk.io.File.enableADS"); if (enableADS != null) { - ENABLE_ADS = "".equals(enableADS) || Boolean.parseBoolean(enableADS); + ENABLE_ADS = !enableADS.equalsIgnoreCase(Boolean.FALSE.toString()); } else { - ENABLE_ADS = false; + ENABLE_ADS = true; } } diff -Nru openjdk-17-17.0.3+7/src/java.base/windows/classes/java/lang/ProcessImpl.java openjdk-17-17.0.4+8/src/java.base/windows/classes/java/lang/ProcessImpl.java --- openjdk-17-17.0.3+7/src/java.base/windows/classes/java/lang/ProcessImpl.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/windows/classes/java/lang/ProcessImpl.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved. * 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,7 +47,6 @@ import jdk.internal.access.JavaIOFileDescriptorAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.ref.CleanerFactory; -import sun.security.action.GetBooleanAction; import sun.security.action.GetPropertyAction; /* This class is for the exclusive use of ProcessBuilder.start() to @@ -269,11 +268,22 @@ // command line parser. The case of the [""] tail escape // sequence could not be realized due to the argument validation // procedure. - int count = countLeadingBackslash(verificationType, s, s.length()); - while (count-- > 0) { - cmdbuf.append(BACKSLASH); // double the number of backslashes + if (verificationType == VERIFICATION_WIN32_SAFE || + verificationType == VERIFICATION_LEGACY) { + int count = countLeadingBackslash(verificationType, s, s.length()); + while (count-- > 0) { + cmdbuf.append(BACKSLASH); // double the number of backslashes + } } cmdbuf.append('"'); + } else if (verificationType == VERIFICATION_WIN32_SAFE && + (s.startsWith("\"") && s.endsWith("\"") && s.length() > 2)) { + // Check that quoted argument does not escape the final quote + cmdbuf.append(s); + int count = countLeadingBackslash(verificationType, s, s.length() - 1); + while (count-- > 0) { + cmdbuf.insert(cmdbuf.length() - 1, BACKSLASH); // double the number of backslashes + } } else { cmdbuf.append(s); } @@ -282,9 +292,7 @@ } /** - * Return the argument without quotes (1st and last) if properly quoted, else the arg. - * A properly quoted string has first and last characters as quote and - * the last quote is not escaped. + * Return the argument without quotes (first and last) if quoted, otherwise the arg. * @param str a string * @return the string without quotes */ @@ -292,9 +300,6 @@ if (!str.startsWith("\"") || !str.endsWith("\"") || str.length() < 2) return str; // no beginning or ending quote, or too short not quoted - if (str.endsWith("\\\"")) { - return str; // not properly quoted, treat as unquoted - } // Strip leading and trailing quotes return str.substring(1, str.length() - 1); } diff -Nru openjdk-17-17.0.3+7/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c openjdk-17-17.0.4+8/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c --- openjdk-17-17.0.3+7/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c 2022-07-14 08:05:38.000000000 +0000 @@ -359,18 +359,17 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPattern (JNIEnv *env, jclass cls, jint numberStyle, jstring jlangtag) { const jchar *langtag; - jstring ret; + jstring ret = NULL; WCHAR * pattern; langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); CHECK_NULL_RETURN(langtag, NULL); pattern = getNumberPattern(langtag, numberStyle); - CHECK_NULL_RETURN(pattern, NULL); - + if (!IS_NULL(pattern)) { + ret = (*env)->NewString(env, pattern, (jsize)wcslen(pattern)); + free(pattern); + } (*env)->ReleaseStringChars(env, jlangtag, langtag); - ret = (*env)->NewString(env, pattern, (jsize)wcslen(pattern)); - free(pattern); - return ret; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java openjdk-17-17.0.4+8/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java --- openjdk-17-17.0.3+7/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,7 +170,7 @@ } int offset = 0; - if (b.isFocusOwner()) { + if (b.isFocusOwner() && b.isFocusPainted()) { offset = 2; altIcon = AquaFocus.createFocusedIcon(altIcon, c, 2); } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java openjdk-17-17.0.4+8/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java --- openjdk-17-17.0.3+7/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -378,9 +378,7 @@ final int x = inX; final int y = inY; final int w = inW; - int h = inH; - - h = metrics.titleBarHeight + inH; + final int h = inH; // paint the background titleBarPainter.state.set(frame.isSelected() ? State.ACTIVE : State.INACTIVE); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java openjdk-17-17.0.4+8/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java --- openjdk-17-17.0.3+7/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,9 +168,9 @@ */ @Override public int getRGBPixel(int x, int y) { - int[] c = new int[1]; - double scale = fDevice.getScaleFactor(); - getScreenPixels(new Rectangle(x, y, (int) scale, (int) scale), c); + int scale = fDevice.getScaleFactor(); + int[] c = new int[scale * scale]; + getScreenPixels(new Rectangle(x, y, scale, scale), c); return c[0]; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java openjdk-17-17.0.4+8/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java --- openjdk-17-17.0.3+7/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,10 +81,57 @@ } } - public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { - final Font prevFont = sg2d.getFont(); - sg2d.setFont(gV.getFont()); + private boolean hasSlotData(GlyphVector gv) { + final int length = gv.getNumGlyphs(); + for (int i = 0; i < length; i++) { + if ((gv.getGlyphCode(i) & CompositeGlyphMapper.SLOTMASK) != 0) { + return true; + } + } + return false; + } + + private Font getSlotFont(Font font, int slot) { + Font2D f2d = FontUtilities.getFont2D(font); + if (f2d instanceof CFont) { + CompositeFont cf = ((CFont)f2d).getCompositeFont2D(); + PhysicalFont pf = cf.getSlotFont(slot); + Font f = new Font(pf.getFontName(null), + font.getStyle(), font.getSize()); + return f; + } + return null; + } + + private GlyphVector getGlyphVectorWithRange(final Font font, final GlyphVector gV, int start, int count) { + int[] glyphs = new int[count]; + for (int i = 0; i < count; i++) { + glyphs[i] = gV.getGlyphCode(start+i) & CompositeGlyphMapper.GLYPHMASK; + } + // Positions should be null to recalculate by native methods, + // if GV was segmented. + StandardGlyphVector sgv = new StandardGlyphVector(font, + gV.getFontRenderContext(), + glyphs, + null, // positions + null, // indices + gV.getLayoutFlags()); + return sgv; + } + + private int getLengthOfSameSlot(final GlyphVector gV, final int targetSlot, final int start, final int length) { + int count = 1; + for (; start + count < length; count++) { + int slot = (gV.getGlyphCode(start + count) & + CompositeGlyphMapper.SLOTMASK) >> 24; + if (targetSlot != slot) { + break; + } + } + return count; + } + private void drawGlyphVectorImpl(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { final long nativeStrikePtr = getNativeStrikePtr(sg2d); if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) { final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData(); @@ -92,6 +139,31 @@ } else { drawGlyphVectorAsShape(sg2d, gV, x, y); } + } + + public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { + final Font prevFont = sg2d.getFont(); + sg2d.setFont(gV.getFont()); + + if (hasSlotData(gV)) { + final int length = gV.getNumGlyphs(); + float[] positions = gV.getGlyphPositions(0, length, null); + int start = 0; + while (start < length) { + int slot = (gV.getGlyphCode(start) & + CompositeGlyphMapper.SLOTMASK) >> 24; + sg2d.setFont(getSlotFont(gV.getFont(), slot)); + int count = getLengthOfSameSlot(gV, slot, start, length); + GlyphVector rangeGV = getGlyphVectorWithRange(sg2d.getFont(), + gV, start, count); + drawGlyphVectorImpl(sg2d, rangeGV, + x + positions[start * 2], + y + positions[start * 2 + 1]); + start += count; + } + } else { + drawGlyphVectorImpl(sg2d, gV, x, y); + } sg2d.setFont(prevFont); } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ColumnAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -1092,11 +1092,11 @@ { JNIEnv* env = [ThreadUtilities getJNIEnv]; + GET_CACCESSIBILITY_CLASS_RETURN(nil); DECLARE_CLASS_RETURN(jc_Container, "java/awt/Container", nil); DECLARE_STATIC_METHOD_RETURN(jm_accessibilityHitTest, sjc_CAccessibility, "accessibilityHitTest", "(Ljava/awt/Container;FF)Ljavax/accessibility/Accessible;", nil); - GET_CACCESSIBILITY_CLASS_RETURN(nil); // Make it into java screen coords point.y = [[[[self view] window] screen] frame].size.height - point.y; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComponentWrapperAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ListRowAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/NavigableTextAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineRowAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabGroupAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.h openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.h --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,9 @@ * * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -321,6 +321,11 @@ jint picY = y; jint picWidth = width; jint picHeight = height; + jsize size = (*env)->GetArrayLength(env, pixels); + if (size < (long) picWidth * picHeight || picWidth < 0 || picHeight < 0) { + JNU_ThrowInternalError(env, "Invalid arguments to get screen pixels"); + return; + } CGRect screenRect = CGRectMake(picX / scale, picY / scale, picWidth / scale, picHeight / scale); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m --- openjdk-17-17.0.3+7/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m 2022-07-14 08:05:38.000000000 +0000 @@ -161,8 +161,8 @@ [sActions setObject:NSAccessibilityPressAction forKey:@"click"]; [sActions setObject:NSAccessibilityIncrementAction forKey:@"increment"]; [sActions setObject:NSAccessibilityDecrementAction forKey:@"decrement"]; - [sActions setObject:NSAccessibilityShowMenuAction forKey:@"togglePopup"]; - [sActions setObject:NSAccessibilityPressAction forKey:@"toggleExpand"]; + [sActions setObject:NSAccessibilityShowMenuAction forKey:@"toggle popup"]; + [sActions setObject:NSAccessibilityPressAction forKey:@"toggleexpand"]; sActionSelectors = [[NSMutableDictionary alloc] initWithCapacity:actionsCount]; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java openjdk-17-17.0.4+8/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java --- openjdk-17-17.0.3+7/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java 2022-07-14 08:05:38.000000000 +0000 @@ -63,7 +63,7 @@ } public int hashCode() { - return theInstance.hashCode(); + return System.identityHashCode(theInstance); } public float[] toRGB(float[] colorvalue) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java openjdk-17-17.0.4+8/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java --- openjdk-17-17.0.3+7/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java 2022-07-14 08:05:38.000000000 +0000 @@ -35,6 +35,7 @@ import javax.imageio.plugins.jpeg.JPEGImageReadParam; import javax.imageio.plugins.jpeg.JPEGQTable; import javax.imageio.plugins.jpeg.JPEGHuffmanTable; +import com.sun.imageio.plugins.common.SimpleCMYKColorSpace; import java.awt.Point; import java.awt.Rectangle; @@ -164,6 +165,12 @@ /** If we need to post-convert in Java, convert with this op */ private ColorConvertOp convert = null; + /** If reading CMYK as an Image, flip the bytes */ + private boolean invertCMYK = false; + + /** Whether to read as a raster */ + private boolean readAsRaster = false; + /** The image we are going to fill */ private BufferedImage image = null; @@ -938,6 +945,32 @@ ArrayList list = new ArrayList(1); switch (colorSpaceCode) { + case JPEG.JCS_YCCK: + case JPEG.JCS_CMYK: + // There's no standard CMYK ColorSpace in JDK so raw.getType() + // will return null so skip that. + // And we can't add RGB because the number of bands is different. + // So need to create our own special that is 4 channels and uses + // the iccCS ColorSpace based on profile data in the image, and + // if there is none, on the internal CMYKColorSpace class + if (iccCS == null) { + iccCS = SimpleCMYKColorSpace.getInstance(); + } + if (iccCS != null) { + list.add(new ImageTypeProducer(colorSpaceCode) { + @Override + protected ImageTypeSpecifier produce() { + int [] bands = {0, 1, 2, 3}; + return ImageTypeSpecifier.createInterleaved + (iccCS, + bands, + DataBuffer.TYPE_BYTE, + false, + false); + } + }); + } + break; case JPEG.JCS_GRAYSCALE: list.add(raw); list.add(getImageType(JPEG.JCS_RGB)); @@ -1019,6 +1052,8 @@ int csType = cs.getType(); convert = null; switch (outColorSpaceCode) { + case JPEG.JCS_CMYK: // Its CMYK in the file + break; case JPEG.JCS_GRAYSCALE: // Its gray in the file if (csType == ColorSpace.TYPE_RGB) { // We want RGB // IJG can do this for us more efficiently @@ -1144,6 +1179,8 @@ private Raster readInternal(int imageIndex, ImageReadParam param, boolean wantRaster) throws IOException { + + readAsRaster = wantRaster; readHeader(imageIndex, false); WritableRaster imRas = null; @@ -1186,6 +1223,16 @@ image = null; } + // Adobe seems to have decided that the bytes in CMYK JPEGs + // should be stored inverted. So we need some extra logic to + // flip them in that case. Don't flip for the raster case + // so code that is reading these as rasters today won't + // see a change in behaviour. + invertCMYK = + (!wantRaster && + ((colorSpaceCode == JPEG.JCS_YCCK) || + (colorSpaceCode == JPEG.JCS_CMYK))); + // Create an intermediate 1-line Raster that will hold the decoded, // subsampled, clipped, band-selected image data in a single // byte-interleaved buffer. The above transformations @@ -1364,6 +1411,21 @@ * After the copy, we notify update listeners. */ private void acceptPixels(int y, boolean progressive) { + + /* + * CMYK JPEGs seems to be universally inverted at the byte level. + * Fix this here before storing. + * For "compatibility" don't do this if the target is a raster. + * Need to do this here in case the application is listening + * for line-by-line updates to the image. + */ + if (invertCMYK) { + byte[] data = ((DataBufferByte)raster.getDataBuffer()).getData(); + for (int i = 0, len = data.length; i < len; i++) { + data[i] = (byte)(0x0ff - (data[i] & 0xff)); + } + } + if (convert != null) { convert.filter(raster, raster); } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java openjdk-17-17.0.4+8/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java --- openjdk-17-17.0.3+7/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java 2022-07-14 08:05:38.000000000 +0000 @@ -132,6 +132,7 @@ private int newAdobeTransform = JPEG.ADOBE_IMPOSSIBLE; // Change if needed private boolean writeDefaultJFIF = false; private boolean writeAdobe = false; + private boolean invertCMYK = false; private JPEGMetadata metadata = null; private boolean sequencePrepared = false; @@ -655,6 +656,7 @@ newAdobeTransform = JPEG.ADOBE_IMPOSSIBLE; // Change if needed writeDefaultJFIF = false; writeAdobe = false; + invertCMYK = false; // By default we'll do no conversion: int inCsType = JPEG.JCS_UNKNOWN; @@ -808,6 +810,14 @@ } } break; + case ColorSpace.TYPE_CMYK: + outCsType = JPEG.JCS_CMYK; + if (jfif != null) { + ignoreJFIF = true; + warningOccurred + (WARNING_IMAGE_METADATA_JFIF_MISMATCH); + } + break; } } } // else no dest, metadata, not an image. Defaults ok @@ -1014,6 +1024,11 @@ System.out.println("outCsType: " + outCsType); } + invertCMYK = + (!rasterOnly && + ((outCsType == JPEG.JCS_YCCK) || + (outCsType == JPEG.JCS_CMYK))); + // Note that getData disables acceleration on buffer, but it is // just a 1-line intermediate data transfer buffer that does not // affect the acceleration of the source image. @@ -1724,6 +1739,12 @@ srcBands); } raster.setRect(sourceLine); + if (invertCMYK) { + byte[] data = ((DataBufferByte)raster.getDataBuffer()).getData(); + for (int i = 0, len = data.length; i < len; i++) { + data[i] = (byte)(0x0ff - (data[i] & 0xff)); + } + } if ((y > 7) && (y%8 == 0)) { // Every 8 scanlines cbLock.lock(); try { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java openjdk-17-17.0.4+8/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java --- openjdk-17-17.0.3+7/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java 2022-07-14 08:05:38.000000000 +0000 @@ -380,6 +380,11 @@ case 0xF7: // sys ex int sysexLength = (int) readVarInt(); + if (sysexLength < 0 || sysexLength > trackLength - pos) { + throw new InvalidMidiDataException("Message length is out of bounds: " + + sysexLength); + } + byte[] sysexData = new byte[sysexLength]; read(sysexData); @@ -392,8 +397,8 @@ // meta int metaType = readUnsigned(); int metaLength = (int) readVarInt(); - if (metaLength < 0) { - throw new InvalidMidiDataException("length out of bounds: " + if (metaLength < 0 || metaLength > trackLength - pos) { + throw new InvalidMidiDataException("Message length is out of bounds: " + metaLength); } final byte[] metaData; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/classes/javax/swing/JTable.java openjdk-17-17.0.4+8/src/java.desktop/share/classes/javax/swing/JTable.java --- openjdk-17-17.0.3+7/src/java.desktop/share/classes/javax/swing/JTable.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/classes/javax/swing/JTable.java 2022-07-14 08:05:38.000000000 +0000 @@ -5481,6 +5481,21 @@ return this; } + + @Override + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new AccessibleBooleanRenderer(); + } + return accessibleContext; + } + + class AccessibleBooleanRenderer extends JCheckBox.AccessibleJCheckBox { + @Override + public AccessibleAction getAccessibleAction() { + return null; + } + } } /** @@ -8402,7 +8417,11 @@ * @return the AccessibleAction, or null */ public AccessibleAction getAccessibleAction() { - return getCurrentAccessibleContext().getAccessibleAction(); + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + return ac.getAccessibleAction(); + } + return null; } /** diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/classes/sun/awt/FontConfiguration.java openjdk-17-17.0.4+8/src/java.desktop/share/classes/sun/awt/FontConfiguration.java --- openjdk-17-17.0.3+7/src/java.desktop/share/classes/sun/awt/FontConfiguration.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/classes/sun/awt/FontConfiguration.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -963,7 +963,9 @@ return fc.newEncoder(); } - if (!charsetName.startsWith("sun.awt.") && !charsetName.equals("default")) { + if (!charsetName.startsWith("sun.awt.") && + !charsetName.equals("default") && + !charsetName.startsWith("sun.font.")) { fc = Charset.forName(charsetName); } else { @SuppressWarnings("removal") diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/legal/freetype.md openjdk-17-17.0.4+8/src/java.desktop/share/legal/freetype.md --- openjdk-17-17.0.3+7/src/java.desktop/share/legal/freetype.md 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/legal/freetype.md 2022-07-14 08:05:38.000000000 +0000 @@ -1,4 +1,4 @@ -## The FreeType Project: Freetype v2.10.4 +## The FreeType Project: Freetype v2.12.0 ### FreeType Notice diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/awt/image/cvutils/img_globals.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/awt/image/cvutils/img_globals.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/awt/image/cvutils/img_globals.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/awt/image/cvutils/img_globals.c 2022-07-14 08:05:38.000000000 +0000 @@ -77,7 +77,7 @@ * color used as an index. */ void -make_sgn_ordered_dither_array(char* oda, int minerr, int maxerr) +make_sgn_ordered_dither_array(signed char* oda, int minerr, int maxerr) { int i, j, k; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/awt/image/cvutils/img_globals.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/awt/image/cvutils/img_globals.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/awt/image/cvutils/img_globals.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/awt/image/cvutils/img_globals.h 2022-07-14 08:05:38.000000000 +0000 @@ -137,7 +137,7 @@ * The type of the error matrix used in the ordered dithering code. */ typedef unsigned char uns_ordered_dither_array[8][8]; -typedef char sgn_ordered_dither_array[8][8]; +typedef signed char sgn_ordered_dither_array[8][8]; /* * The function provided for constructing the ordered dithering error @@ -148,7 +148,7 @@ JNIEXPORT void JNICALL make_uns_ordered_dither_array(uns_ordered_dither_array oda, int quantum); -extern void make_sgn_ordered_dither_array(char* oda, int errmin, int errmax); +extern void make_sgn_ordered_dither_array(signed char* oda, int errmin, int errmax); /* * The function provided for calculating the contents of the ImgCMData diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.h 2022-07-14 08:05:38.000000000 +0000 @@ -44,7 +44,7 @@ #define DeclareByteIndexedStoreVars(PREFIX) \ int PREFIX ## XDither, PREFIX ## YDither, PREFIX ## RepPrims; \ - char *PREFIX ## rerr, *PREFIX ## gerr, *PREFIX ## berr; \ + signed char *PREFIX ## rerr, *PREFIX ## gerr, *PREFIX ## berr; \ unsigned char *PREFIX ## InvLut; #define SetByteIndexedStoreVarsYPos(PREFIX, pRasInfo, LOC) \ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/java2d/loops/UshortIndexed.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/java2d/loops/UshortIndexed.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/java2d/loops/UshortIndexed.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/java2d/loops/UshortIndexed.h 2022-07-14 08:05:38.000000000 +0000 @@ -51,7 +51,7 @@ #define DeclareUshortIndexedStoreVars(PREFIX) \ int PREFIX ## XDither, PREFIX ## YDither; \ - char *PREFIX ## rerr, *PREFIX ## gerr, *PREFIX ## berr; \ + signed char *PREFIX ## rerr, *PREFIX ## gerr, *PREFIX ## berr; \ unsigned char *PREFIX ## InvLut; #define SetUshortIndexedStoreVarsYPos(PREFIX, pRasInfo, LOC) \ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/java2d/SurfaceData.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/java2d/SurfaceData.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libawt/java2d/SurfaceData.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libawt/java2d/SurfaceData.h 2022-07-14 08:05:38.000000000 +0000 @@ -129,9 +129,9 @@ * array of bytes indexed by RxGxB where each component is reduced to 5 * bits of precision before indexing. * - * char *redErrTable; - * char *grnErrTable; - * char *bluErrTable; + * signed char *redErrTable; + * signed char *grnErrTable; + * signed char *bluErrTable; * [Requires SD_LOCK_INVCOLOR] * Pointers to the beginning of the ordered dither color error tables * for the colormap. The error tables are formatted as an 8x8 array @@ -159,9 +159,9 @@ unsigned int lutSize; /* # colors in colormap */ jint *lutBase; /* Pointer to colormap[0] */ unsigned char *invColorTable; /* Inverse color table */ - char *redErrTable; /* Red ordered dither table */ - char *grnErrTable; /* Green ordered dither table */ - char *bluErrTable; /* Blue ordered dither table */ + signed char *redErrTable; /* Red ordered dither table */ + signed char *grnErrTable; /* Green ordered dither table */ + signed char *bluErrTable; /* Blue ordered dither table */ int *invGrayTable; /* Inverse gray table */ int representsPrimaries; /* whether cmap represents primary colors */ union { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * ANSI-specific configuration file (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Build macros of the FreeType 2 library. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -777,6 +777,18 @@ #define FT_COLOR_H + /************************************************************************** + * + * @macro: + * FT_OTSVG_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which handles the OpenType 'SVG~' glyphs. + */ +#define FT_OTSVG_H + + /* */ /* These header files don't need to be included by the user. */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftmodule.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftmodule.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftmodule.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftmodule.h 2022-07-14 08:05:38.000000000 +0000 @@ -19,12 +19,15 @@ // FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) // FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) // FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) +// FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) FT_USE_MODULE( FT_Module_Class, psaux_module_class ) FT_USE_MODULE( FT_Module_Class, psnames_module_class ) FT_USE_MODULE( FT_Module_Class, pshinter_module_class ) -FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) -// FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) +// FT_USE_MODULE( FT_Renderer_Class, ft_sdf_renderer_class ) +// FT_USE_MODULE( FT_Renderer_Class, ft_bitmap_sdf_renderer_class ) +// FT_USE_MODULE( FT_Renderer_Class, ft_svg_renderer_class ) /* EOF */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * User-selectable configuration macros (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -105,8 +105,7 @@ * * ``` * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ - * cff:no-stem-darkening=1 \ - * autofitter:warping=1 + * cff:no-stem-darkening=1 * ``` * */ @@ -220,6 +219,10 @@ * If you use a build system like cmake or the `configure` script, * options set by those programs have precedence, overwriting the value * here with the configured one. + * + * If you use the GNU make build system directly (that is, without the + * `configure` script) and you define this macro, you also have to pass + * `SYSTEM_ZLIB=yes` as an argument to make. */ /* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ @@ -433,6 +436,23 @@ /************************************************************************** * + * Logging + * + * Compiling FreeType in debug or trace mode makes FreeType write error + * and trace log messages to `stderr`. Enabling this macro + * automatically forces the `FT_DEBUG_LEVEL_ERROR` and + * `FT_DEBUG_LEVEL_TRACE` macros and allows FreeType to write error and + * trace log messages to a file instead of `stderr`. For writing logs + * to a file, FreeType uses an the external `dlg` library (the source + * code is in `src/dlg`). + * + * This option needs a C99 compiler. + */ +/* #define FT_DEBUG_LOGGING */ + + + /************************************************************************** + * * Autofitter debugging * * If `FT_DEBUG_AUTOFIT` is defined, FreeType provides some means to @@ -509,6 +529,20 @@ /************************************************************************** * + * OpenType SVG Glyph Support + * + * Setting this macro enables support for OpenType SVG glyphs. By + * default, FreeType can only fetch SVG documents. However, it can also + * render them if external rendering hook functions are plugged in at + * runtime. + * + * More details on the hooks can be found in file `otsvg.h`. + */ +/* #define FT_CONFIG_OPTION_SVG */ + + + /************************************************************************** + * * Error Strings * * If this macro is set, `FT_Error_String` will return meaningful @@ -894,24 +928,6 @@ /************************************************************************** * - * Compile 'autofit' module with warp hinting. The idea of the warping - * code is to slightly scale and shift a glyph within a single dimension so - * that as much of its segments are aligned (more or less) on the grid. To - * find out the optimal scaling and shifting value, various parameter - * combinations are tried and scored. - * - * You can switch warping on and off with the `warping` property of the - * auto-hinter (see file `ftdriver.h` for more information; by default it - * is switched off). - * - * This experimental option is not active if the rendering mode is - * `FT_RENDER_MODE_LIGHT`. - */ -#define AF_CONFIG_OPTION_USE_WARPER - - - /************************************************************************** - * * Use TrueType-like size metrics for 'light' auto-hinting. * * It is strongly recommended to avoid this option, which exists only to @@ -962,6 +978,21 @@ /* + * The TT_SUPPORT_COLRV1 macro is defined to indicate to clients that this + * version of FreeType has support for 'COLR' v1 API. This definition is + * useful to FreeType clients that want to build in support for 'COLR' v1 + * depending on a tip-of-tree checkout before it is officially released in + * FreeType, and while the feature cannot yet be tested against using + * version macros. Don't change this macro. This may be removed once the + * feature is in a FreeType release version and version macros can be used + * to test for availability. + */ +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define TT_SUPPORT_COLRV1 +#endif + + + /* * Check CFF darkening parameters. The checks are the same as in function * `cff_property_set` in file `cffdrivr.c`. */ @@ -989,8 +1020,8 @@ #error "Invalid CFF darkening parameters!" #endif -FT_END_HEADER +FT_END_HEADER #endif /* FTOPTION_H_ */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * ANSI-specific library and header configuration file (specification * only). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -43,7 +43,8 @@ * * `UINT_MAX` and `ULONG_MAX` are used to automatically compute the size of * `int` and `long` in bytes at compile-time. So far, this works for all - * platforms the library has been tested on. + * platforms the library has been tested on. We also check `ULLONG_MAX` + * to see whether we can use 64-bit `long long` later on. * * Note that on the extremely rare platforms that do not provide integer * types that are _exactly_ 16 and 32~bits wide (e.g., some old Crays where @@ -66,6 +67,15 @@ #define FT_LONG_MIN LONG_MIN #define FT_LONG_MAX LONG_MAX #define FT_ULONG_MAX ULONG_MAX +#ifdef LLONG_MAX +#define FT_LLONG_MAX LLONG_MAX +#endif +#ifdef LLONG_MIN +#define FT_LLONG_MIN LLONG_MIN +#endif +#ifdef ULLONG_MAX +#define FT_ULLONG_MAX ULLONG_MAX +#endif /************************************************************************** diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType integer types definitions. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -60,6 +60,18 @@ #endif /* !defined(FT_SIZEOF_LONG) */ +#ifndef FT_SIZEOF_LONG_LONG + + /* The size of a `long long` type if available */ +#if defined( FT_ULLONG_MAX ) && FT_ULLONG_MAX >= 0xFFFFFFFFFFFFFFFFULL +#define FT_SIZEOF_LONG_LONG ( 64 / FT_CHAR_BIT ) +#else +#define FT_SIZEOF_LONG_LONG 0 +#endif + +#endif /* !defined(FT_SIZEOF_LONG_LONG) */ + + /************************************************************************** * * @section: @@ -174,15 +186,17 @@ #endif - /* determine whether we have a 64-bit `int` type for platforms without */ - /* Autoconf */ + /* determine whether we have a 64-bit integer type */ #if FT_SIZEOF_LONG == ( 64 / FT_CHAR_BIT ) - /* `FT_LONG64` must be defined if a 64-bit type is available */ -#define FT_LONG64 #define FT_INT64 long #define FT_UINT64 unsigned long +#elif FT_SIZEOF_LONG_LONG >= ( 64 / FT_CHAR_BIT ) + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + /************************************************************************** * * A 64-bit data type may create compilation problems if you compile in @@ -192,16 +206,9 @@ */ #elif !defined( __STDC__ ) || defined( FT_CONFIG_OPTION_FORCE_INT64 ) -#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 199901L - -#define FT_LONG64 -#define FT_INT64 long long int -#define FT_UINT64 unsigned long long int - -#elif defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ +#if defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ /* this compiler provides the `__int64` type */ -#define FT_LONG64 #define FT_INT64 __int64 #define FT_UINT64 unsigned __int64 @@ -211,32 +218,30 @@ /* to test the compiler version. */ /* this compiler provides the `__int64` type */ -#define FT_LONG64 #define FT_INT64 __int64 #define FT_UINT64 unsigned __int64 -#elif defined( __WATCOMC__ ) /* Watcom C++ */ +#elif defined( __WATCOMC__ ) && __WATCOMC__ >= 1100 /* Watcom C++ */ - /* Watcom doesn't provide 64-bit data types */ +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int #elif defined( __MWERKS__ ) /* Metrowerks CodeWarrior */ -#define FT_LONG64 #define FT_INT64 long long int #define FT_UINT64 unsigned long long int #elif defined( __GNUC__ ) /* GCC provides the `long long` type */ -#define FT_LONG64 #define FT_INT64 long long int #define FT_UINT64 unsigned long long int -#endif /* __STDC_VERSION__ >= 199901L */ +#endif /* !__STDC__ */ #endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ -#ifdef FT_LONG64 +#ifdef FT_INT64 typedef FT_INT64 FT_Int64; typedef FT_UINT64 FT_UInt64; #endif diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Mac/OS X support configuration header. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Define a set of compiler macros used in public FreeType headers. * - * Copyright (C) 2020 by + * Copyright (C) 2020-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -103,6 +103,7 @@ */ #define FT_EXPORT( x ) FT_PUBLIC_FUNCTION_ATTRIBUTE extern x + /* * `FT_UNUSED` indicates that a given parameter is not used -- this is * only used to get rid of unpleasant compiler warnings. @@ -115,6 +116,23 @@ #endif + /* + * Support for casts in both C and C++. + */ +#ifdef __cplusplus +#define FT_STATIC_CAST( type, var ) static_cast(var) +#define FT_REINTERPRET_CAST( type, var ) reinterpret_cast(var) + +#define FT_STATIC_BYTE_CAST( type, var ) \ + static_cast( static_cast( var ) ) +#else +#define FT_STATIC_CAST( type, var ) (type)(var) +#define FT_REINTERPRET_CAST( type, var ) (type)(var) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) +#endif + + FT_END_HEADER #endif /* FREETYPE_CONFIG_PUBLIC_MACROS_H_ */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType high-level API and common types (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -33,6 +33,34 @@ /************************************************************************** * * @section: + * preamble + * + * @title: + * Preamble + * + * @abstract: + * What FreeType is and isn't + * + * @description: + * FreeType is a library that provides access to glyphs in font files. It + * scales the glyph images and their metrics to a requested size, and it + * rasterizes the glyph images to produce pixel or subpixel alpha coverage + * bitmaps. + * + * Note that FreeType is _not_ a text layout engine. You have to use + * higher-level libraries like HarfBuzz, Pango, or ICU for that. + * + * Note also that FreeType does _not_ perform alpha blending or + * compositing the resulting bitmaps or pixmaps by itself. Use your + * favourite graphics library (for example, Cairo or Skia) to further + * process FreeType's output. + * + */ + + + /************************************************************************** + * + * @section: * header_inclusion * * @title: @@ -125,6 +153,9 @@ * FT_FACE_FLAG_GLYPH_NAMES * FT_FACE_FLAG_EXTERNAL_STREAM * FT_FACE_FLAG_HINTER + * FT_FACE_FLAG_SVG + * FT_FACE_FLAG_SBIX + * FT_FACE_FLAG_SBIX_OVERLAY * * FT_HAS_HORIZONTAL * FT_HAS_VERTICAL @@ -133,6 +164,9 @@ * FT_HAS_GLYPH_NAMES * FT_HAS_COLOR * FT_HAS_MULTIPLE_MASTERS + * FT_HAS_SVG + * FT_HAS_SBIX + * FT_HAS_SBIX_OVERLAY * * FT_IS_SFNT * FT_IS_SCALABLE @@ -176,6 +210,7 @@ * FT_Size_RequestRec * FT_Size_Request * FT_Set_Transform + * FT_Get_Transform * FT_Load_Glyph * FT_Get_Char_Index * FT_Get_First_Char @@ -196,6 +231,7 @@ * FT_LOAD_NO_SCALE * FT_LOAD_NO_HINTING * FT_LOAD_NO_BITMAP + * FT_LOAD_SBITS_ONLY * FT_LOAD_NO_AUTOHINT * FT_LOAD_COLOR * @@ -493,13 +529,15 @@ * size. * * @note: - * An @FT_Face has one _active_ @FT_Size object that is used by functions - * like @FT_Load_Glyph to determine the scaling transformation that in - * turn is used to load and hint glyphs and metrics. + * An @FT_Face has one _active_ `FT_Size` object that is used by + * functions like @FT_Load_Glyph to determine the scaling transformation + * that in turn is used to load and hint glyphs and metrics. * - * You can use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, @FT_Request_Size + * A newly created `FT_Size` object contains only meaningless zero values. + * You must use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, @FT_Request_Size * or even @FT_Select_Size to change the content (i.e., the scaling - * values) of the active @FT_Size. + * values) of the active `FT_Size`. Otherwise, the scaling and hinting + * will not be performed. * * You can use @FT_New_Size to create additional size objects for a given * @FT_Face, but they won't be used by other functions until you activate @@ -587,11 +625,12 @@ */ #ifndef FT_ENC_TAG -#define FT_ENC_TAG( value, a, b, c, d ) \ - value = ( ( (FT_UInt32)(a) << 24 ) | \ - ( (FT_UInt32)(b) << 16 ) | \ - ( (FT_UInt32)(c) << 8 ) | \ - (FT_UInt32)(d) ) + +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( FT_STATIC_BYTE_CAST( FT_UInt32, a ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( FT_UInt32, b ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( FT_UInt32, c ) << 8 ) | \ + FT_STATIC_BYTE_CAST( FT_UInt32, d ) ) #endif /* FT_ENC_TAG */ @@ -701,11 +740,16 @@ * Same as FT_ENCODING_JOHAB. Deprecated. * * @note: - * By default, FreeType enables a Unicode charmap and tags it with - * `FT_ENCODING_UNICODE` when it is either provided or can be generated - * from PostScript glyph name dictionaries in the font file. All other - * encodings are considered legacy and tagged only if explicitly defined - * in the font file. Otherwise, `FT_ENCODING_NONE` is used. + * When loading a font, FreeType makes a Unicode charmap active if + * possible (either if the font provides such a charmap, or if FreeType + * can synthesize one from PostScript glyph name dictionaries; in either + * case, the charmap is tagged with `FT_ENCODING_UNICODE`). If such a + * charmap is synthesized, it is placed at the first position of the + * charmap array. + * + * All other encodings are considered legacy and tagged only if + * explicitly defined in the font file. Otherwise, `FT_ENCODING_NONE` is + * used. * * `FT_ENCODING_NONE` is set by the BDF and PCF drivers if the charmap is * neither Unicode nor ISO-8859-1 (otherwise it is set to @@ -1193,6 +1237,19 @@ * altered with @FT_Set_MM_Design_Coordinates, * @FT_Set_Var_Design_Coordinates, or @FT_Set_Var_Blend_Coordinates. * This flag is unset by a call to @FT_Set_Named_Instance. + * + * FT_FACE_FLAG_SVG :: + * [Since 2.12] The face has an 'SVG~' OpenType table. + * + * FT_FACE_FLAG_SBIX :: + * [Since 2.12] The face has an 'sbix' OpenType table *and* outlines. + * For such fonts, @FT_FACE_FLAG_SCALABLE is not set by default to + * retain backward compatibility. + * + * FT_FACE_FLAG_SBIX_OVERLAY :: + * [Since 2.12] The face has an 'sbix' OpenType table where outlines + * should be drawn on top of bitmap strikes. + * */ #define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) #define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) @@ -1210,6 +1267,9 @@ #define FT_FACE_FLAG_TRICKY ( 1L << 13 ) #define FT_FACE_FLAG_COLOR ( 1L << 14 ) #define FT_FACE_FLAG_VARIATION ( 1L << 15 ) +#define FT_FACE_FLAG_SVG ( 1L << 16 ) +#define FT_FACE_FLAG_SBIX ( 1L << 17 ) +#define FT_FACE_FLAG_SBIX_OVERLAY ( 1L << 18 ) /************************************************************************** @@ -1452,6 +1512,124 @@ /************************************************************************** * + * @macro: + * FT_HAS_SVG + * + * @description: + * A macro that returns true whenever a face object contains an 'SVG~' + * OpenType table. + * + * @since: + * 2.12 + */ +#define FT_HAS_SVG( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SVG ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SBIX + * + * @description: + * A macro that returns true whenever a face object contains an 'sbix' + * OpenType table *and* outline glyphs. + * + * Currently, FreeType only supports bitmap glyphs in PNG format for this + * table (i.e., JPEG and TIFF formats are unsupported, as are + * Apple-specific formats not part of the OpenType specification). + * + * @note: + * For backward compatibility, a font with an 'sbix' table is treated as + * a bitmap-only face. Using @FT_Open_Face with + * @FT_PARAM_TAG_IGNORE_SBIX, an application can switch off 'sbix' + * handling so that the face is treated as an ordinary outline font with + * scalable outlines. + * + * Here is some pseudo code that roughly illustrates how to implement + * 'sbix' handling according to the OpenType specification. + * + * ``` + * if ( FT_HAS_SBIX( face ) ) + * { + * // open font as a scalable one without sbix handling + * FT_Face face2; + * FT_Parameter param = { FT_PARAM_TAG_IGNORE_SBIX, NULL }; + * FT_Open_Args args = { FT_OPEN_PARAMS | ..., + * ..., + * 1, ¶m }; + * + * + * FT_Open_Face( library, &args, 0, &face2 ); + * + * available_size` as necessary into + * `preferred_sizes`[*]> + * + * for ( i = 0; i < face->num_fixed_sizes; i++ ) + * { + * size = preferred_sizes[i].size; + * + * error = FT_Set_Pixel_Sizes( face, size, size ); + * + * + * // check whether we have a glyph in a bitmap strike + * error = FT_Load_Glyph( face, + * glyph_index, + * FT_LOAD_SBITS_ONLY | + * FT_LOAD_BITMAP_METRICS_ONLY ); + * if ( error == FT_Err_Invalid_Argument ) + * continue; + * else if ( error ) + * + * else + * break; + * } + * + * if ( i != face->num_fixed_sizes ) + * + * + * if ( i == face->num_fixed_sizes || + * FT_HAS_SBIX_OVERLAY( face ) ) + * + * } + * ``` + * + * [*] Assuming a target value of 400dpi and available strike sizes 100, + * 200, 300, and 400dpi, a possible order might be [400, 200, 300, 100]: + * scaling 200dpi to 400dpi usually gives better results than scaling + * 300dpi to 400dpi; it is also much faster. However, scaling 100dpi to + * 400dpi can yield a too pixelated result, thus the preference might be + * 300dpi over 100dpi. + * + * @since: + * 2.12 + */ +#define FT_HAS_SBIX( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SBIX_OVERLAY + * + * @description: + * A macro that returns true whenever a face object contains an 'sbix' + * OpenType table with bit~1 in its `flags` field set, instructing the + * application to overlay the bitmap strike with the corresponding + * outline glyph. See @FT_HAS_SBIX for pseudo code how to use it. + * + * @since: + * 2.12 + */ +#define FT_HAS_SBIX_OVERLAY( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX_OVERLAY ) ) + + + /************************************************************************** + * * @enum: * FT_STYLE_FLAG_XXX * @@ -2065,7 +2243,8 @@ * The size in bytes of the file in memory. * * pathname :: - * A pointer to an 8-bit file pathname. The pointer is not owned by + * A pointer to an 8-bit file pathname, which must be a C~string (i.e., + * no null bytes except at the very end). The pointer is not owned by * FreeType. * * stream :: @@ -2084,8 +2263,7 @@ * Extra parameters passed to the font driver when opening a new face. * * @note: - * The stream type is determined by the contents of `flags` that are - * tested in the following order by @FT_Open_Face: + * The stream type is determined by the contents of `flags`: * * If the @FT_OPEN_MEMORY bit is set, assume that this is a memory file * of `memory_size` bytes, located at `memory_address`. The data are not @@ -2098,6 +2276,9 @@ * Otherwise, if the @FT_OPEN_PATHNAME bit is set, assume that this is a * normal file and use `pathname` to open it. * + * If none of the above bits are set or if multiple are set at the same + * time, the flags are invalid and @FT_Open_Face fails. + * * If the @FT_OPEN_DRIVER bit is set, @FT_Open_Face only tries to open * the file with the driver whose handler is in `driver`. * @@ -2150,6 +2331,13 @@ * FreeType error code. 0~means success. * * @note: + * The `pathname` string should be recognizable as such by a standard + * `fopen` call on your system; in particular, this means that `pathname` + * must not contain null bytes. If that is not sufficient to address all + * file name possibilities (for example, to handle wide character file + * names on Windows in UTF-16 encoding) you might use @FT_Open_Face to + * pass a memory array or a stream object instead. + * * Use @FT_Done_Face to destroy the created @FT_Face object (along with * its slot and sizes). */ @@ -2270,6 +2458,10 @@ * See the discussion of reference counters in the description of * @FT_Reference_Face. * + * If `FT_OPEN_STREAM` is set in `args->flags`, the stream in + * `args->stream` is automatically closed before this function returns + * any error (including `FT_Err_Invalid_Argument`). + * * @example: * To loop over all faces, use code similar to the following snippet * (omitting the error handling). @@ -2428,6 +2620,7 @@ * * @since: * 2.4.2 + * */ FT_EXPORT( FT_Error ) FT_Reference_Face( FT_Face face ); @@ -2652,8 +2845,8 @@ * 'https://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html'. * * Contrary to @FT_Set_Char_Size, this function doesn't have special code - * to normalize zero-valued widths, heights, or resolutions (which lead - * to errors in most cases). + * to normalize zero-valued widths, heights, or resolutions, which are + * treated as @FT_LOAD_NO_SCALE. * * Don't use this function if you are using the FreeType cache API. */ @@ -2769,7 +2962,7 @@ * * load_flags :: * A flag indicating what to load for this glyph. The @FT_LOAD_XXX - * constants can be used to control the glyph loading process (e.g., + * flags can be used to control the glyph loading process (e.g., * whether the outline should be scaled, whether to load bitmaps or * not, whether to hint the outline, etc). * @@ -2777,8 +2970,10 @@ * FreeType error code. 0~means success. * * @note: - * The loaded glyph may be transformed. See @FT_Set_Transform for the - * details. + * For proper scaling and hinting, the active @FT_Size object owned by + * the face has to be meaningfully initialized by calling + * @FT_Set_Char_Size before this function, for example. The loaded + * glyph may be transformed. See @FT_Set_Transform for the details. * * For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument` is returned * for invalid CID values (this is, for CID values that don't have a @@ -2868,6 +3063,8 @@ * * FT_LOAD_NO_SCALE :: * Don't scale the loaded outline glyph but keep it in font units. + * This flag is also assumed if @FT_Size owned by the face was not + * properly initialized. * * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and * unsets @FT_LOAD_RENDER. @@ -2898,6 +3095,15 @@ * * @FT_LOAD_NO_SCALE always sets this flag. * + * FT_LOAD_SBITS_ONLY :: + * [Since 2.12] This is the opposite of @FT_LOAD_NO_BITMAP, more or + * less: @FT_Load_Glyph returns `FT_Err_Invalid_Argument` if the face + * contains a bitmap strike for the given size (or the strike selected + * by @FT_Select_Size) but there is no glyph in the strike. + * + * Note that this load flag was part of FreeType since version 2.0.6 + * but previously tagged as internal. + * * FT_LOAD_VERTICAL_LAYOUT :: * Load the glyph for vertical text layout. In particular, the * `advance` value in the @FT_GlyphSlotRec structure is set to the @@ -2954,21 +3160,31 @@ * Disable the auto-hinter. See also the note below. * * FT_LOAD_COLOR :: - * Load colored glyphs. There are slight differences depending on the - * font format. + * Load colored glyphs. FreeType searches in the following order; + * there are slight differences depending on the font format. * - * [Since 2.5] Load embedded color bitmap images. The resulting color - * bitmaps, if available, will have the @FT_PIXEL_MODE_BGRA format, - * with pre-multiplied color channels. If the flag is not set and - * color bitmaps are found, they are converted to 256-level gray - * bitmaps, using the @FT_PIXEL_MODE_GRAY format. + * [Since 2.5] Load embedded color bitmap images (provided + * @FT_LOAD_NO_BITMAP is not set). The resulting color bitmaps, if + * available, have the @FT_PIXEL_MODE_BGRA format, with pre-multiplied + * color channels. If the flag is not set and color bitmaps are found, + * they are converted to 256-level gray bitmaps, using the + * @FT_PIXEL_MODE_GRAY format. + * + * [Since 2.12] If the glyph index maps to an entry in the face's + * 'SVG~' table, load the associated SVG document from this table and + * set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG. + * Note that FreeType itself can't render SVG documents; however, the + * library provides hooks to seamlessly integrate an external renderer. + * See sections @ot_svg_driver and @svg_fonts for more. * - * [Since 2.10, experimental] If the glyph index contains an entry in + * [Since 2.10, experimental] If the glyph index maps to an entry in * the face's 'COLR' table with a 'CPAL' palette table (as defined in * the OpenType specification), make @FT_Render_Glyph provide a default * blending of the color glyph layers associated with the glyph index, * using the same bitmap format as embedded color bitmap images. This - * is mainly for convenience; for full control of color layers use + * is mainly for convenience and works only for glyphs in 'COLR' v0 + * tables (or glyphs in 'COLR' v1 tables that exclusively use v0 + * features). For full control of color layers use * @FT_Get_Color_Glyph_Layer and FreeType's color functions like * @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering * so that the client application can handle blending by itself. @@ -3019,19 +3235,20 @@ * */ #define FT_LOAD_DEFAULT 0x0 -#define FT_LOAD_NO_SCALE ( 1L << 0 ) -#define FT_LOAD_NO_HINTING ( 1L << 1 ) -#define FT_LOAD_RENDER ( 1L << 2 ) -#define FT_LOAD_NO_BITMAP ( 1L << 3 ) -#define FT_LOAD_VERTICAL_LAYOUT ( 1L << 4 ) -#define FT_LOAD_FORCE_AUTOHINT ( 1L << 5 ) -#define FT_LOAD_CROP_BITMAP ( 1L << 6 ) -#define FT_LOAD_PEDANTIC ( 1L << 7 ) -#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ( 1L << 9 ) +#define FT_LOAD_NO_SCALE ( 1L << 0 ) +#define FT_LOAD_NO_HINTING ( 1L << 1 ) +#define FT_LOAD_RENDER ( 1L << 2 ) +#define FT_LOAD_NO_BITMAP ( 1L << 3 ) +#define FT_LOAD_VERTICAL_LAYOUT ( 1L << 4 ) +#define FT_LOAD_FORCE_AUTOHINT ( 1L << 5 ) +#define FT_LOAD_CROP_BITMAP ( 1L << 6 ) +#define FT_LOAD_PEDANTIC ( 1L << 7 ) +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ( 1L << 9 ) #define FT_LOAD_NO_RECURSE ( 1L << 10 ) #define FT_LOAD_IGNORE_TRANSFORM ( 1L << 11 ) #define FT_LOAD_MONOCHROME ( 1L << 12 ) #define FT_LOAD_LINEAR_DESIGN ( 1L << 13 ) +#define FT_LOAD_SBITS_ONLY ( 1L << 14 ) #define FT_LOAD_NO_AUTOHINT ( 1L << 15 ) /* Bits 16-19 are used by `FT_LOAD_TARGET_` */ #define FT_LOAD_COLOR ( 1L << 20 ) @@ -3041,8 +3258,8 @@ /* */ /* used internally only by certain font drivers */ -#define FT_LOAD_ADVANCE_ONLY ( 1L << 8 ) -#define FT_LOAD_SBITS_ONLY ( 1L << 14 ) +#define FT_LOAD_ADVANCE_ONLY ( 1L << 8 ) +#define FT_LOAD_SVG_ONLY ( 1L << 23 ) /************************************************************************** @@ -3132,7 +3349,7 @@ * necessary to empty the cache after a mode switch to avoid false hits. * */ -#define FT_LOAD_TARGET_( x ) ( (FT_Int32)( (x) & 15 ) << 16 ) +#define FT_LOAD_TARGET_( x ) ( FT_STATIC_CAST( FT_Int32, (x) & 15 ) << 16 ) #define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) #define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) @@ -3151,7 +3368,8 @@ * @FT_LOAD_TARGET_XXX value. * */ -#define FT_LOAD_TARGET_MODE( x ) ( (FT_Render_Mode)( ( (x) >> 16 ) & 15 ) ) +#define FT_LOAD_TARGET_MODE( x ) \ + FT_STATIC_CAST( FT_Render_Mode, ( (x) >> 16 ) & 15 ) /************************************************************************** @@ -3172,11 +3390,12 @@ * A pointer to the transformation's 2x2 matrix. Use `NULL` for the * identity matrix. * delta :: - * A pointer to the translation vector. Use `NULL` for the null vector. + * A pointer to the translation vector. Use `NULL` for the null + * vector. * * @note: * This function is provided as a convenience, but keep in mind that - * @FT_Matrix coefficients are only 16.16 fixed point values, which can + * @FT_Matrix coefficients are only 16.16 fixed-point values, which can * limit the accuracy of the results. Using floating-point computations * to perform the transform directly in client code instead will always * yield better numbers. @@ -3197,6 +3416,39 @@ /************************************************************************** * + * @function: + * FT_Get_Transform + * + * @description: + * Return the transformation that is applied to glyph images when they + * are loaded into a glyph slot through @FT_Load_Glyph. See + * @FT_Set_Transform for more details. + * + * @input: + * face :: + * A handle to the source face object. + * + * @output: + * matrix :: + * A pointer to a transformation's 2x2 matrix. Set this to NULL if you + * are not interested in the value. + * + * delta :: + * A pointer a translation vector. Set this to NULL if you are not + * interested in the value. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Get_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /************************************************************************** + * * @enum: * FT_Render_Mode * @@ -3213,6 +3465,10 @@ * correction to correctly render non-monochrome glyph bitmaps onto a * surface; see @FT_Render_Glyph. * + * The @FT_RENDER_MODE_SDF is a special render mode that uses up to 256 + * distance values, indicating the signed distance from the grid position + * to the nearest outline. + * * @values: * FT_RENDER_MODE_NORMAL :: * Default render mode; it corresponds to 8-bit anti-aliased bitmaps. @@ -3238,11 +3494,87 @@ * bitmaps that are 3~times the height of the original glyph outline in * pixels and use the @FT_PIXEL_MODE_LCD_V mode. * + * FT_RENDER_MODE_SDF :: + * This mode corresponds to 8-bit, single-channel signed distance field + * (SDF) bitmaps. Each pixel in the SDF grid is the value from the + * pixel's position to the nearest glyph's outline. The distances are + * calculated from the center of the pixel and are positive if they are + * filled by the outline (i.e., inside the outline) and negative + * otherwise. Check the note below on how to convert the output values + * to usable data. + * * @note: * The selected render mode only affects vector glyphs of a font. * Embedded bitmaps often have a different pixel mode like * @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform them * into 8-bit pixmaps. + * + * For @FT_RENDER_MODE_SDF the output bitmap buffer contains normalized + * distances that are packed into unsigned 8-bit values. To get pixel + * values in floating point representation use the following pseudo-C + * code for the conversion. + * + * ``` + * // Load glyph and render using FT_RENDER_MODE_SDF, + * // then use the output buffer as follows. + * + * ... + * FT_Byte buffer = glyph->bitmap->buffer; + * + * + * for pixel in buffer + * { + * // `sd` is the signed distance and `spread` is the current spread; + * // the default spread is 2 and can be changed. + * + * float sd = (float)pixel - 128.0f; + * + * + * // Convert to pixel values. + * sd = ( sd / 128.0f ) * spread; + * + * // Store `sd` in a buffer or use as required. + * } + * + * ``` + * + * FreeType has two rasterizers for generating SDF, namely: + * + * 1. `sdf` for generating SDF directly from glyph's outline, and + * + * 2. `bsdf` for generating SDF from rasterized bitmaps. + * + * Depending on the glyph type (i.e., outline or bitmap), one of the two + * rasterizers is chosen at runtime and used for generating SDFs. To + * force the use of `bsdf` you should render the glyph with any of the + * FreeType's other rendering modes (e.g., `FT_RENDER_MODE_NORMAL`) and + * then re-render with `FT_RENDER_MODE_SDF`. + * + * There are some issues with stability and possible failures of the SDF + * renderers (specifically `sdf`). + * + * 1. The `sdf` rasterizer is sensitive to really small features (e.g., + * sharp turns that are less than 1~pixel) and imperfections in the + * glyph's outline, causing artifacts in the final output. + * + * 2. The `sdf` rasterizer has limited support for handling intersecting + * contours and *cannot* handle self-intersecting contours whatsoever. + * Self-intersection happens when a single connected contour intersect + * itself at some point; having these in your font definitely pose a + * problem to the rasterizer and cause artifacts, too. + * + * 3. Generating SDF for really small glyphs may result in undesirable + * output; the pixel grid (which stores distance information) becomes + * too coarse. + * + * 4. Since the output buffer is normalized, precision at smaller spreads + * is greater than precision at larger spread values because the + * output range of [0..255] gets mapped to a smaller SDF range. A + * spread of~2 should be sufficient in most cases. + * + * Points (1) and (2) can be avoided by using the `bsdf` rasterizer, + * which is more stable than the `sdf` rasterizer in general. + * */ typedef enum FT_Render_Mode_ { @@ -3251,6 +3583,7 @@ FT_RENDER_MODE_MONO, FT_RENDER_MODE_LCD, FT_RENDER_MODE_LCD_V, + FT_RENDER_MODE_SDF, FT_RENDER_MODE_MAX @@ -3282,7 +3615,7 @@ * @FT_Render_Mode for a list of possible values. * * If @FT_RENDER_MODE_NORMAL is used, a previous call of @FT_Load_Glyph - * with flag @FT_LOAD_COLOR makes FT_Render_Glyph provide a default + * with flag @FT_LOAD_COLOR makes `FT_Render_Glyph` provide a default * blending of colored glyph layers associated with the current glyph * slot (provided the font contains such layers) instead of rendering * the glyph slot's outline. This is an experimental feature; see @@ -3292,9 +3625,6 @@ * FreeType error code. 0~means success. * * @note: - * To get meaningful results, font scaling values must be set with - * functions like @FT_Set_Char_Size before calling `FT_Render_Glyph`. - * * When FreeType outputs a bitmap of a glyph, it really outputs an alpha * coverage map. If a pixel is completely covered by a filled-in * outline, the bitmap contains 0xFF at that pixel, meaning that @@ -3338,7 +3668,8 @@ * * which is known as the OVER operator. * - * To correctly composite an antialiased pixel of a glyph onto a surface, + * To correctly composite an anti-aliased pixel of a glyph onto a + * surface, * * 1. take the foreground and background colors (e.g., in sRGB space) * and apply gamma to get them in a linear space, @@ -4018,168 +4349,6 @@ /************************************************************************** * * @section: - * layer_management - * - * @title: - * Glyph Layer Management - * - * @abstract: - * Retrieving and manipulating OpenType's 'COLR' table data. - * - * @description: - * The functions described here allow access of colored glyph layer data - * in OpenType's 'COLR' tables. - */ - - - /************************************************************************** - * - * @struct: - * FT_LayerIterator - * - * @description: - * This iterator object is needed for @FT_Get_Color_Glyph_Layer. - * - * @fields: - * num_layers :: - * The number of glyph layers for the requested glyph index. Will be - * set by @FT_Get_Color_Glyph_Layer. - * - * layer :: - * The current layer. Will be set by @FT_Get_Color_Glyph_Layer. - * - * p :: - * An opaque pointer into 'COLR' table data. The caller must set this - * to `NULL` before the first call of @FT_Get_Color_Glyph_Layer. - */ - typedef struct FT_LayerIterator_ - { - FT_UInt num_layers; - FT_UInt layer; - FT_Byte* p; - - } FT_LayerIterator; - - - /************************************************************************** - * - * @function: - * FT_Get_Color_Glyph_Layer - * - * @description: - * This is an interface to the 'COLR' table in OpenType fonts to - * iteratively retrieve the colored glyph layers associated with the - * current glyph slot. - * - * https://docs.microsoft.com/en-us/typography/opentype/spec/colr - * - * The glyph layer data for a given glyph index, if present, provides an - * alternative, multi-color glyph representation: Instead of rendering - * the outline or bitmap with the given glyph index, glyphs with the - * indices and colors returned by this function are rendered layer by - * layer. - * - * The returned elements are ordered in the z~direction from bottom to - * top; the 'n'th element should be rendered with the associated palette - * color and blended on top of the already rendered layers (elements 0, - * 1, ..., n-1). - * - * @input: - * face :: - * A handle to the parent face object. - * - * base_glyph :: - * The glyph index the colored glyph layers are associated with. - * - * @inout: - * iterator :: - * An @FT_LayerIterator object. For the first call you should set - * `iterator->p` to `NULL`. For all following calls, simply use the - * same object again. - * - * @output: - * aglyph_index :: - * The glyph index of the current layer. - * - * acolor_index :: - * The color index into the font face's color palette of the current - * layer. The value 0xFFFF is special; it doesn't reference a palette - * entry but indicates that the text foreground color should be used - * instead (to be set up by the application outside of FreeType). - * - * The color palette can be retrieved with @FT_Palette_Select. - * - * @return: - * Value~1 if everything is OK. If there are no more layers (or if there - * are no layers at all), value~0 gets returned. In case of an error, - * value~0 is returned also. - * - * @note: - * This function is necessary if you want to handle glyph layers by - * yourself. In particular, functions that operate with @FT_GlyphRec - * objects (like @FT_Get_Glyph or @FT_Glyph_To_Bitmap) don't have access - * to this information. - * - * Note that @FT_Render_Glyph is able to handle colored glyph layers - * automatically if the @FT_LOAD_COLOR flag is passed to a previous call - * to @FT_Load_Glyph. [This is an experimental feature.] - * - * @example: - * ``` - * FT_Color* palette; - * FT_LayerIterator iterator; - * - * FT_Bool have_layers; - * FT_UInt layer_glyph_index; - * FT_UInt layer_color_index; - * - * - * error = FT_Palette_Select( face, palette_index, &palette ); - * if ( error ) - * palette = NULL; - * - * iterator.p = NULL; - * have_layers = FT_Get_Color_Glyph_Layer( face, - * glyph_index, - * &layer_glyph_index, - * &layer_color_index, - * &iterator ); - * - * if ( palette && have_layers ) - * { - * do - * { - * FT_Color layer_color; - * - * - * if ( layer_color_index == 0xFFFF ) - * layer_color = text_foreground_color; - * else - * layer_color = palette[layer_color_index]; - * - * // Load and render glyph `layer_glyph_index', then - * // blend resulting pixmap (using color `layer_color') - * // with previously created pixmaps. - * - * } while ( FT_Get_Color_Glyph_Layer( face, - * glyph_index, - * &layer_glyph_index, - * &layer_color_index, - * &iterator ) ); - * } - * ``` - */ - FT_EXPORT( FT_Bool ) - FT_Get_Color_Glyph_Layer( FT_Face face, - FT_UInt base_glyph, - FT_UInt *aglyph_index, - FT_UInt *acolor_index, - FT_LayerIterator* iterator ); - - - /************************************************************************** - * - * @section: * base_interface * */ @@ -4267,6 +4436,7 @@ * * @since: * 2.3.8 + * */ FT_EXPORT( FT_UShort ) FT_Get_FSType_Flags( FT_Face face ); @@ -4360,6 +4530,7 @@ * * @since: * 2.3.6 + * */ FT_EXPORT( FT_UInt ) FT_Face_GetCharVariantIndex( FT_Face face, @@ -4396,6 +4567,7 @@ * * @since: * 2.3.6 + * */ FT_EXPORT( FT_Int ) FT_Face_GetCharVariantIsDefault( FT_Face face, @@ -4427,6 +4599,7 @@ * * @since: * 2.3.6 + * */ FT_EXPORT( FT_UInt32* ) FT_Face_GetVariantSelectors( FT_Face face ); @@ -4460,6 +4633,7 @@ * * @since: * 2.3.6 + * */ FT_EXPORT( FT_UInt32* ) FT_Face_GetVariantsOfChar( FT_Face face, @@ -4494,6 +4668,7 @@ * * @since: * 2.3.6 + * */ FT_EXPORT( FT_UInt32* ) FT_Face_GetCharsOfVariant( FT_Face face, @@ -4766,8 +4941,8 @@ * */ #define FREETYPE_MAJOR 2 -#define FREETYPE_MINOR 10 -#define FREETYPE_PATCH 4 +#define FREETYPE_MINOR 12 +#define FREETYPE_PATCH 0 /************************************************************************** @@ -4829,6 +5004,7 @@ * * @since: * 2.3.5 + * */ FT_EXPORT( FT_Bool ) FT_Face_CheckTrueTypePatents( FT_Face face ); @@ -4857,6 +5033,7 @@ * * @since: * 2.3.5 + * */ FT_EXPORT( FT_Bool ) FT_Face_SetUnpatentedHinting( FT_Face face, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Quick computation of advance widths (specification only). * - * Copyright (C) 2008-2020 by + * Copyright (C) 2008-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType exact bbox computation (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType API for accessing BDF-specific strings (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (specification). * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftchapters.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftchapters.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftchapters.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftchapters.h 2022-07-14 08:05:38.000000000 +0000 @@ -15,6 +15,7 @@ * General Remarks * * @sections: + * preamble * header_inclusion * user_allocation * @@ -61,6 +62,7 @@ * cid_fonts * pfr_fonts * winfnt_fonts + * svg_fonts * font_formats * gasp_table * @@ -81,6 +83,7 @@ * t1_cid_driver * tt_driver * pcf_driver + * ot_svg_driver * properties * parameter_tags * lcd_rendering @@ -123,6 +126,7 @@ * gzip * lzw * bzip2 + * debugging_apis * */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information (specification). * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * Dereg Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType's glyph color management (specification). * - * Copyright (C) 2018-2020 by + * Copyright (C) 2018-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -302,6 +302,1411 @@ FT_Palette_Set_Foreground_Color( FT_Face face, FT_Color foreground_color ); + + /************************************************************************** + * + * @section: + * layer_management + * + * @title: + * Glyph Layer Management + * + * @abstract: + * Retrieving and manipulating OpenType's 'COLR' table data. + * + * @description: + * The functions described here allow access of colored glyph layer data + * in OpenType's 'COLR' tables. + */ + + + /************************************************************************** + * + * @struct: + * FT_LayerIterator + * + * @description: + * This iterator object is needed for @FT_Get_Color_Glyph_Layer. + * + * @fields: + * num_layers :: + * The number of glyph layers for the requested glyph index. Will be + * set by @FT_Get_Color_Glyph_Layer. + * + * layer :: + * The current layer. Will be set by @FT_Get_Color_Glyph_Layer. + * + * p :: + * An opaque pointer into 'COLR' table data. The caller must set this + * to `NULL` before the first call of @FT_Get_Color_Glyph_Layer. + */ + typedef struct FT_LayerIterator_ + { + FT_UInt num_layers; + FT_UInt layer; + FT_Byte* p; + + } FT_LayerIterator; + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_Layer + * + * @description: + * This is an interface to the 'COLR' table in OpenType fonts to + * iteratively retrieve the colored glyph layers associated with the + * current glyph slot. + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/colr + * + * The glyph layer data for a given glyph index, if present, provides an + * alternative, multi-color glyph representation: Instead of rendering + * the outline or bitmap with the given glyph index, glyphs with the + * indices and colors returned by this function are rendered layer by + * layer. + * + * The returned elements are ordered in the z~direction from bottom to + * top; the 'n'th element should be rendered with the associated palette + * color and blended on top of the already rendered layers (elements 0, + * 1, ..., n-1). + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @inout: + * iterator :: + * An @FT_LayerIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * aglyph_index :: + * The glyph index of the current layer. + * + * acolor_index :: + * The color index into the font face's color palette of the current + * layer. The value 0xFFFF is special; it doesn't reference a palette + * entry but indicates that the text foreground color should be used + * instead (to be set up by the application outside of FreeType). + * + * The color palette can be retrieved with @FT_Palette_Select. + * + * @return: + * Value~1 if everything is OK. If there are no more layers (or if there + * are no layers at all), value~0 gets returned. In case of an error, + * value~0 is returned also. + * + * @note: + * This function is necessary if you want to handle glyph layers by + * yourself. In particular, functions that operate with @FT_GlyphRec + * objects (like @FT_Get_Glyph or @FT_Glyph_To_Bitmap) don't have access + * to this information. + * + * Note that @FT_Render_Glyph is able to handle colored glyph layers + * automatically if the @FT_LOAD_COLOR flag is passed to a previous call + * to @FT_Load_Glyph. [This is an experimental feature.] + * + * @example: + * ``` + * FT_Color* palette; + * FT_LayerIterator iterator; + * + * FT_Bool have_layers; + * FT_UInt layer_glyph_index; + * FT_UInt layer_color_index; + * + * + * error = FT_Palette_Select( face, palette_index, &palette ); + * if ( error ) + * palette = NULL; + * + * iterator.p = NULL; + * have_layers = FT_Get_Color_Glyph_Layer( face, + * glyph_index, + * &layer_glyph_index, + * &layer_color_index, + * &iterator ); + * + * if ( palette && have_layers ) + * { + * do + * { + * FT_Color layer_color; + * + * + * if ( layer_color_index == 0xFFFF ) + * layer_color = text_foreground_color; + * else + * layer_color = palette[layer_color_index]; + * + * // Load and render glyph `layer_glyph_index', then + * // blend resulting pixmap (using color `layer_color') + * // with previously created pixmaps. + * + * } while ( FT_Get_Color_Glyph_Layer( face, + * glyph_index, + * &layer_glyph_index, + * &layer_color_index, + * &iterator ) ); + * } + * ``` + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_Layer( FT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ); + + + /************************************************************************** + * + * @enum: + * FT_PaintFormat + * + * @description: + * Enumeration describing the different paint format types of the v1 + * extensions to the 'COLR' table, see + * 'https://github.com/googlefonts/colr-gradients-spec'. + * + * The enumeration values losely correspond with the format numbers of + * the specification: FreeType always returns a fully specified 'Paint' + * structure for the 'Transform', 'Translate', 'Scale', 'Rotate', and + * 'Skew' table types even though the specification has different formats + * depending on whether or not a center is specified, whether the scale + * is uniform in x and y~direction or not, etc. Also, only non-variable + * format identifiers are listed in this enumeration; as soon as support + * for variable 'COLR' v1 fonts is implemented, interpolation is + * performed dependent on axis coordinates, which are configured on the + * @FT_Face through @FT_Set_Var_Design_Coordinates. This implies that + * always static, readily interpolated values are returned in the 'Paint' + * structures. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef enum FT_PaintFormat_ + { + FT_COLR_PAINTFORMAT_COLR_LAYERS = 1, + FT_COLR_PAINTFORMAT_SOLID = 2, + FT_COLR_PAINTFORMAT_LINEAR_GRADIENT = 4, + FT_COLR_PAINTFORMAT_RADIAL_GRADIENT = 6, + FT_COLR_PAINTFORMAT_SWEEP_GRADIENT = 8, + FT_COLR_PAINTFORMAT_GLYPH = 10, + FT_COLR_PAINTFORMAT_COLR_GLYPH = 11, + FT_COLR_PAINTFORMAT_TRANSFORM = 12, + FT_COLR_PAINTFORMAT_TRANSLATE = 14, + FT_COLR_PAINTFORMAT_SCALE = 16, + FT_COLR_PAINTFORMAT_ROTATE = 24, + FT_COLR_PAINTFORMAT_SKEW = 28, + FT_COLR_PAINTFORMAT_COMPOSITE = 32, + FT_COLR_PAINT_FORMAT_MAX = 33, + FT_COLR_PAINTFORMAT_UNSUPPORTED = 255 + + } FT_PaintFormat; + + + /************************************************************************** + * + * @struct: + * FT_ColorStopIterator + * + * @description: + * This iterator object is needed for @FT_Get_Colorline_Stops. It keeps + * state while iterating over the stops of an @FT_ColorLine, + * representing the `ColorLine` struct of the v1 extensions to 'COLR', + * see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * num_color_stops :: + * The number of color stops for the requested glyph index. Set by + * @FT_Get_Colorline_Stops. + * + * current_color_stop :: + * The current color stop. Set by @FT_Get_Colorline_Stops. + * + * p :: + * An opaque pointer into 'COLR' table data. The caller must set this + * to `NULL` before the first call of @FT_Get_Colorline_Stops. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_ColorStopIterator_ + { + FT_UInt num_color_stops; + FT_UInt current_color_stop; + + FT_Byte* p; + + } FT_ColorStopIterator; + + + /************************************************************************** + * + * @struct: + * FT_ColorIndex + * + * @description: + * A structure representing a `ColorIndex` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * palette_index :: + * The palette index into a 'CPAL' palette. + * + * alpha :: + * Alpha transparency value multiplied with the value from 'CPAL'. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_ColorIndex_ + { + FT_UInt16 palette_index; + FT_F2Dot14 alpha; + + } FT_ColorIndex; + + + /************************************************************************** + * + * @struct: + * FT_ColorStop + * + * @description: + * A structure representing a `ColorStop` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * stop_offset :: + * The stop offset between 0 and 1 along the gradient. + * + * color :: + * The color information for this stop, see @FT_ColorIndex. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_ColorStop_ + { + FT_F2Dot14 stop_offset; + FT_ColorIndex color; + + } FT_ColorStop; + + + /************************************************************************** + * + * @enum: + * FT_PaintExtend + * + * @description: + * An enumeration representing the 'Extend' mode of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * It describes how the gradient fill continues at the other boundaries. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef enum FT_PaintExtend_ + { + FT_COLR_PAINT_EXTEND_PAD = 0, + FT_COLR_PAINT_EXTEND_REPEAT = 1, + FT_COLR_PAINT_EXTEND_REFLECT = 2 + + } FT_PaintExtend; + + + /************************************************************************** + * + * @struct: + * FT_ColorLine + * + * @description: + * A structure representing a `ColorLine` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * It describes a list of color stops along the defined gradient. + * + * @fields: + * extend :: + * The extend mode at the outer boundaries, see @FT_PaintExtend. + * + * color_stop_iterator :: + * The @FT_ColorStopIterator used to enumerate and retrieve the + * actual @FT_ColorStop's. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_ColorLine_ + { + FT_PaintExtend extend; + FT_ColorStopIterator color_stop_iterator; + + } FT_ColorLine; + + + /************************************************************************** + * + * @struct: + * FT_Affine23 + * + * @description: + * A structure used to store a 2x3 matrix. Coefficients are in + * 16.16 fixed-point format. The computation performed is + * + * ``` + * x' = x*xx + y*xy + dx + * y' = x*yx + y*yy + dy + * ``` + * + * @fields: + * xx :: + * Matrix coefficient. + * + * xy :: + * Matrix coefficient. + * + * dx :: + * x translation. + * + * yx :: + * Matrix coefficient. + * + * yy :: + * Matrix coefficient. + * + * dy :: + * y translation. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_Affine_23_ + { + FT_Fixed xx, xy, dx; + FT_Fixed yx, yy, dy; + + } FT_Affine23; + + + /************************************************************************** + * + * @enum: + * FT_Composite_Mode + * + * @description: + * An enumeration listing the 'COLR' v1 composite modes used in + * @FT_PaintComposite. For more details on each paint mode, see + * 'https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators'. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef enum FT_Composite_Mode_ + { + FT_COLR_COMPOSITE_CLEAR = 0, + FT_COLR_COMPOSITE_SRC = 1, + FT_COLR_COMPOSITE_DEST = 2, + FT_COLR_COMPOSITE_SRC_OVER = 3, + FT_COLR_COMPOSITE_DEST_OVER = 4, + FT_COLR_COMPOSITE_SRC_IN = 5, + FT_COLR_COMPOSITE_DEST_IN = 6, + FT_COLR_COMPOSITE_SRC_OUT = 7, + FT_COLR_COMPOSITE_DEST_OUT = 8, + FT_COLR_COMPOSITE_SRC_ATOP = 9, + FT_COLR_COMPOSITE_DEST_ATOP = 10, + FT_COLR_COMPOSITE_XOR = 11, + FT_COLR_COMPOSITE_PLUS = 12, + FT_COLR_COMPOSITE_SCREEN = 13, + FT_COLR_COMPOSITE_OVERLAY = 14, + FT_COLR_COMPOSITE_DARKEN = 15, + FT_COLR_COMPOSITE_LIGHTEN = 16, + FT_COLR_COMPOSITE_COLOR_DODGE = 17, + FT_COLR_COMPOSITE_COLOR_BURN = 18, + FT_COLR_COMPOSITE_HARD_LIGHT = 19, + FT_COLR_COMPOSITE_SOFT_LIGHT = 20, + FT_COLR_COMPOSITE_DIFFERENCE = 21, + FT_COLR_COMPOSITE_EXCLUSION = 22, + FT_COLR_COMPOSITE_MULTIPLY = 23, + FT_COLR_COMPOSITE_HSL_HUE = 24, + FT_COLR_COMPOSITE_HSL_SATURATION = 25, + FT_COLR_COMPOSITE_HSL_COLOR = 26, + FT_COLR_COMPOSITE_HSL_LUMINOSITY = 27, + FT_COLR_COMPOSITE_MAX = 28 + + } FT_Composite_Mode; + + + /************************************************************************** + * + * @struct: + * FT_OpaquePaint + * + * @description: + * A structure representing an offset to a `Paint` value stored in any + * of the paint tables of a 'COLR' v1 font. Compare Offset<24> there. + * When 'COLR' v1 paint tables represented by FreeType objects such as + * @FT_PaintColrLayers, @FT_PaintComposite, or @FT_PaintTransform + * reference downstream nested paint tables, we do not immediately + * retrieve them but encapsulate their location in this type. Use + * @FT_Get_Paint to retrieve the actual @FT_COLR_Paint object that + * describes the details of the respective paint table. + * + * @fields: + * p :: + * An internal offset to a Paint table, needs to be set to NULL before + * passing this struct as an argument to @FT_Get_Paint. + * + * insert_root_transform :: + * An internal boolean to track whether an initial root transform is + * to be provided. Do not set this value. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_Opaque_Paint_ + { + FT_Byte* p; + FT_Bool insert_root_transform; + } FT_OpaquePaint; + + + /************************************************************************** + * + * @struct: + * FT_PaintColrLayers + * + * @description: + * A structure representing a `PaintColrLayers` table of a 'COLR' v1 + * font. This table describes a set of layers that are to be composited + * with composite mode `FT_COLR_COMPOSITE_SRC_OVER`. The return value + * of this function is an @FT_LayerIterator initialized so that it can + * be used with @FT_Get_Paint_Layers to retrieve the @FT_OpaquePaint + * objects as references to each layer. + * + * @fields: + * layer_iterator :: + * The layer iterator that describes the layers of this paint. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintColrLayers_ + { + FT_LayerIterator layer_iterator; + + } FT_PaintColrLayers; + + + /************************************************************************** + * + * @struct: + * FT_PaintSolid + * + * @description: + * A structure representing a `PaintSolid` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * Using a `PaintSolid` value means that the glyph layer filled with + * this paint is solid-colored and does not contain a gradient. + * + * @fields: + * color :: + * The color information for this solid paint, see @FT_ColorIndex. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintSolid_ + { + FT_ColorIndex color; + + } FT_PaintSolid; + + + /************************************************************************** + * + * @struct: + * FT_PaintLinearGradient + * + * @description: + * A structure representing a `PaintLinearGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a linear gradient. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * p0 :: + * The starting point of the gradient definition in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * p1 :: + * The end point of the gradient definition in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * p2 :: + * Optional point~p2 to rotate the gradient in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * Otherwise equal to~p0. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintLinearGradient_ + { + FT_ColorLine colorline; + + /* TODO: Potentially expose those as x0, y0 etc. */ + FT_Vector p0; + FT_Vector p1; + FT_Vector p2; + + } FT_PaintLinearGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintRadialGradient + * + * @description: + * A structure representing a `PaintRadialGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled filled with a radial + * gradient. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * c0 :: + * The center of the starting point of the radial gradient in font + * units represented as a 16.16 fixed-point `FT_Vector`. + * + * r0 :: + * The radius of the starting circle of the radial gradient in font + * units represented as a 16.16 fixed-point value. + * + * c1 :: + * The center of the end point of the radial gradient in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * r1 :: + * The radius of the end circle of the radial gradient in font + * units represented as a 16.16 fixed-point value. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintRadialGradient_ + { + FT_ColorLine colorline; + + FT_Vector c0; + FT_Pos r0; + FT_Vector c1; + FT_Pos r1; + + } FT_PaintRadialGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintSweepGradient + * + * @description: + * A structure representing a `PaintSweepGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a sweep gradient + * from `start_angle` to `end_angle`. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * center :: + * The center of the sweep gradient in font units represented as a + * vector of 16.16 fixed-point values. + * + * start_angle :: + * The start angle of the sweep gradient in 16.16 fixed-point + * format specifying degrees divided by 180.0 (as in the + * spec). Multiply by 180.0f to receive degrees value. Values are + * given counter-clockwise, starting from the (positive) y~axis. + * + * end_angle :: + * The end angle of the sweep gradient in 16.16 fixed-point + * format specifying degrees divided by 180.0 (as in the + * spec). Multiply by 180.0f to receive degrees value. Values are + * given counter-clockwise, starting from the (positive) y~axis. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintSweepGradient_ + { + FT_ColorLine colorline; + + FT_Vector center; + FT_Fixed start_angle; + FT_Fixed end_angle; + + } FT_PaintSweepGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintGlyph + * + * @description: + * A structure representing a 'COLR' v1 `PaintGlyph` paint table. + * + * @fields: + * paint :: + * An opaque paint object pointing to a `Paint` table that serves as + * the fill for the glyph ID. + * + * glyphID :: + * The glyph ID from the 'glyf' table, which serves as the contour + * information that is filled with paint. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintGlyph_ + { + FT_OpaquePaint paint; + FT_UInt glyphID; + + } FT_PaintGlyph; + + + /************************************************************************** + * + * @struct: + * FT_PaintColrGlyph + * + * @description: + * A structure representing a 'COLR' v1 `PaintColorGlyph` paint table. + * + * @fields: + * glyphID :: + * The glyph ID from the `BaseGlyphV1List` table that is drawn for + * this paint. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintColrGlyph_ + { + FT_UInt glyphID; + + } FT_PaintColrGlyph; + + + /************************************************************************** + * + * @struct: + * FT_PaintTransform + * + * @description: + * A structure representing a 'COLR' v1 `PaintTransform` paint table. + * + * @fields: + * paint :: + * An opaque paint that is subject to being transformed. + * + * affine :: + * A 2x3 transformation matrix in @FT_Affine23 format containing + * 16.16 fixed-point values. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintTransform_ + { + FT_OpaquePaint paint; + FT_Affine23 affine; + + } FT_PaintTransform; + + + /************************************************************************** + * + * @struct: + * FT_PaintTranslate + * + * @description: + * A structure representing a 'COLR' v1 `PaintTranslate` paint table. + * Used for translating downstream paints by a given x and y~delta. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * rotated. + * + * dx :: + * Translation in x~direction in font units represented as a + * 16.16 fixed-point value. + * + * dy :: + * Translation in y~direction in font units represented as a + * 16.16 fixed-point value. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintTranslate_ + { + FT_OpaquePaint paint; + + FT_Fixed dx; + FT_Fixed dy; + + } FT_PaintTranslate; + + + /************************************************************************** + * + * @struct: + * FT_PaintScale + * + * @description: + * A structure representing all of the 'COLR' v1 'PaintScale*' paint + * tables. Used for scaling downstream paints by a given x and y~scale, + * with a given center. This structure is used for all 'PaintScale*' + * types that are part of specification; fields of this structure are + * filled accordingly. If there is a center, the center values are set, + * otherwise they are set to the zero coordinate. If the source font + * file has 'PaintScaleUniform*' set, the scale values are set + * accordingly to the same value. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * scaled. + * + * scale_x :: + * Scale factor in x~direction represented as a + * 16.16 fixed-point value. + * + * scale_y :: + * Scale factor in y~direction represented as a + * 16.16 fixed-point value. + * + * center_x :: + * x~coordinate of center point to scale from represented as a + * 16.16 fixed-point value. + * + * center_y :: + * y~coordinate of center point to scale from represented as a + * 16.16 fixed-point value. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward-compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintScale_ + { + FT_OpaquePaint paint; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintScale; + + + /************************************************************************** + * + * @struct: + * FT_PaintRotate + * + * @description: + * A structure representing a 'COLR' v1 `PaintRotate` paint table. Used + * for rotating downstream paints with a given center and angle. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * rotated. + * + * angle :: + * The rotation angle that is to be applied in degrees divided by + * 180.0 (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees value. + * + * center_x :: + * The x~coordinate of the pivot point of the rotation in font + * units) represented as a 16.16 fixed-point value. + * + * center_y :: + * The y~coordinate of the pivot point of the rotation in font + * units represented as a 16.16 fixed-point value. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + + typedef struct FT_PaintRotate_ + { + FT_OpaquePaint paint; + + FT_Fixed angle; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintRotate; + + + /************************************************************************** + * + * @struct: + * FT_PaintSkew + * + * @description: + * A structure representing a 'COLR' v1 `PaintSkew` paint table. Used + * for skewing or shearing downstream paints by a given center and + * angle. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * skewed. + * + * x_skew_angle :: + * The skewing angle in x~direction in degrees divided by 180.0 + * (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees. + * + * y_skew_angle :: + * The skewing angle in y~direction in degrees divided by 180.0 + * (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees. + * + * center_x :: + * The x~coordinate of the pivot point of the skew in font units + * represented as a 16.16 fixed-point value. + * + * center_y :: + * The y~coordinate of the pivot point of the skew in font units + * represented as a 16.16 fixed-point value. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintSkew_ + { + FT_OpaquePaint paint; + + FT_Fixed x_skew_angle; + FT_Fixed y_skew_angle; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintSkew; + + + /************************************************************************** + * + * @struct: + * FT_PaintComposite + * + * @description: + * A structure representing a 'COLR'v1 `PaintComposite` paint table. + * Used for compositing two paints in a 'COLR' v1 directed acycling + * graph. + * + * @fields: + * source_paint :: + * An @FT_OpaquePaint object referencing the source that is to be + * composited. + * + * composite_mode :: + * An @FT_Composite_Mode enum value determining the composition + * operation. + * + * backdrop_paint :: + * An @FT_OpaquePaint object referencing the backdrop paint that + * `source_paint` is composited onto. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_PaintComposite_ + { + FT_OpaquePaint source_paint; + FT_Composite_Mode composite_mode; + FT_OpaquePaint backdrop_paint; + + } FT_PaintComposite; + + + /************************************************************************** + * + * @union: + * FT_COLR_Paint + * + * @description: + * A union object representing format and details of a paint table of a + * 'COLR' v1 font, see + * 'https://github.com/googlefonts/colr-gradients-spec'. Use + * @FT_Get_Paint to retrieve a @FT_COLR_Paint for an @FT_OpaquePaint + * object. + * + * @fields: + * format :: + * The gradient format for this Paint structure. + * + * u :: + * Union of all paint table types: + * + * * @FT_PaintColrLayers + * * @FT_PaintGlyph + * * @FT_PaintSolid + * * @FT_PaintLinearGradient + * * @FT_PaintRadialGradient + * * @FT_PaintSweepGradient + * * @FT_PaintTransform + * * @FT_PaintTranslate + * * @FT_PaintRotate + * * @FT_PaintSkew + * * @FT_PaintComposite + * * @FT_PaintColrGlyph + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_COLR_Paint_ + { + FT_PaintFormat format; + + union + { + FT_PaintColrLayers colr_layers; + FT_PaintGlyph glyph; + FT_PaintSolid solid; + FT_PaintLinearGradient linear_gradient; + FT_PaintRadialGradient radial_gradient; + FT_PaintSweepGradient sweep_gradient; + FT_PaintTransform transform; + FT_PaintTranslate translate; + FT_PaintScale scale; + FT_PaintRotate rotate; + FT_PaintSkew skew; + FT_PaintComposite composite; + FT_PaintColrGlyph colr_glyph; + + } u; + + } FT_COLR_Paint; + + + /************************************************************************** + * + * @enum: + * FT_Color_Root_Transform + * + * @description: + * An enumeration to specify whether @FT_Get_Color_Glyph_Paint is to + * return a root transform to configure the client's graphics context + * matrix. + * + * @values: + * FT_COLOR_INCLUDE_ROOT_TRANSFORM :: + * Do include the root transform as the initial @FT_COLR_Paint object. + * + * FT_COLOR_NO_ROOT_TRANSFORM :: + * Do not output an initial root transform. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef enum FT_Color_Root_Transform_ + { + FT_COLOR_INCLUDE_ROOT_TRANSFORM, + FT_COLOR_NO_ROOT_TRANSFORM, + + FT_COLOR_ROOT_TRANSFORM_MAX + + } FT_Color_Root_Transform; + + + /************************************************************************** + * + * @struct: + * FT_ClipBox + * + * @description: + * A structure representing a 'COLR' v1 'ClipBox' table. 'COLR' v1 + * glyphs may optionally define a clip box for aiding allocation or + * defining a maximum drawable region. Use @FT_Get_Color_Glyph_ClipBox + * to retrieve it. + * + * @fields: + * bottom_left :: + * The bottom left corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * top_left :: + * The top left corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * top_right :: + * The top right corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * bottom_right :: + * The bottom right corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * @since: + * 2.12 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + typedef struct FT_ClipBox_ + { + FT_Vector bottom_left; + FT_Vector top_left; + FT_Vector top_right; + FT_Vector bottom_right; + + } FT_ClipBox; + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_Paint + * + * @description: + * This is the starting point and interface to color gradient + * information in a 'COLR' v1 table in OpenType fonts to recursively + * retrieve the paint tables for the directed acyclic graph of a colored + * glyph, given a glyph ID. + * + * https://github.com/googlefonts/colr-gradients-spec + * + * In a 'COLR' v1 font, each color glyph defines a directed acyclic + * graph of nested paint tables, such as `PaintGlyph`, `PaintSolid`, + * `PaintLinearGradient`, `PaintRadialGradient`, and so on. Using this + * function and specifying a glyph ID, one retrieves the root paint + * table for this glyph ID. + * + * This function allows control whether an initial root transform is + * returned to configure scaling, transform, and translation correctly + * on the client's graphics context. The initial root transform is + * computed and returned according to the values configured for @FT_Size + * and @FT_Set_Transform on the @FT_Face object, see below for details + * of the `root_transform` parameter. This has implications for a + * client 'COLR' v1 implementation: When this function returns an + * initially computed root transform, at the time of executing the + * @FT_PaintGlyph operation, the contours should be retrieved using + * @FT_Load_Glyph at unscaled, untransformed size. This is because the + * root transform applied to the graphics context will take care of + * correct scaling. + * + * Alternatively, to allow hinting of contours, at the time of executing + * @FT_Load_Glyph, the current graphics context transformation matrix + * can be decomposed into a scaling matrix and a remainder, and + * @FT_Load_Glyph can be used to retrieve the contours at scaled size. + * Care must then be taken to blit or clip to the graphics context with + * taking this remainder transformation into account. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the root paint table. + * + * root_transform :: + * Specifies whether an initially computed root is returned by the + * @FT_PaintTransform operation to account for the activated size + * (see @FT_Activate_Size) and the configured transform and translate + * (see @FT_Set_Transform). + * + * This root transform is returned before nodes of the glyph graph of + * the font are returned. Subsequent @FT_COLR_Paint structures + * contain unscaled and untransformed values. The inserted root + * transform enables the client application to apply an initial + * transform to its graphics context. When executing subsequent + * FT_COLR_Paint operations, values from @FT_COLR_Paint operations + * will ultimately be correctly scaled because of the root transform + * applied to the graphics context. Use + * @FT_COLOR_INCLUDE_ROOT_TRANSFORM to include the root transform, use + * @FT_COLOR_NO_ROOT_TRANSFORM to not include it. The latter may be + * useful when traversing the 'COLR' v1 glyph graph and reaching a + * @FT_PaintColrGlyph. When recursing into @FT_PaintColrGlyph and + * painting that inline, no additional root transform is needed as it + * has already been applied to the graphics context at the beginning + * of drawing this glyph. + * + * @output: + * paint :: + * The @FT_OpaquePaint object that references the actual paint table. + * + * The respective actual @FT_COLR_Paint object is retrieved via + * @FT_Get_Paint. + * + * @return: + * Value~1 if everything is OK. If no color glyph is found, or the root + * paint could not be retrieved, value~0 gets returned. In case of an + * error, value~0 is returned also. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_Paint( FT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_ClipBox + * + * @description: + * Search for a 'COLR' v1 clip box for the specified `base_glyph` and + * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information + * if one is found. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the clip box. + * + * @output: + * clip_box :: + * The clip box for the requested `base_glyph` if one is found. The + * clip box is computed taking scale and transformations configured on + * the @FT_Face into account. @FT_ClipBox contains @FT_Vector values + * in 26.6 format. + * + * @return: + * Value~1 if a clip box is found. If no clip box is found or an error + * occured, value~0 is returned. + * + * @note: + * To retrieve the clip box in font units, reset scale to units-per-em + * and remove transforms configured using @FT_Set_Transform. + * + * @since: + * 2.12 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_ClipBox( FT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + + /************************************************************************** + * + * @function: + * FT_Get_Paint_Layers + * + * @description: + * Access the layers of a `PaintColrLayers` table. + * + * If the root paint of a color glyph, or a nested paint of a 'COLR' + * glyph is a `PaintColrLayers` table, this function retrieves the + * layers of the `PaintColrLayers` table. + * + * The @FT_PaintColrLayers object contains an @FT_LayerIterator, which + * is used here to iterate over the layers. Each layer is returned as + * an @FT_OpaquePaint object, which then can be used with @FT_Get_Paint + * to retrieve the actual paint object. + * + * @input: + * face :: + * A handle to the parent face object. + * + * @inout: + * iterator :: + * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which + * the layers are to be retrieved. The internal state of the iterator + * is incremented after one call to this function for retrieving one + * layer. + * + * @output: + * paint :: + * The @FT_OpaquePaint object that references the actual paint table. + * The respective actual @FT_COLR_Paint object is retrieved via + * @FT_Get_Paint. + * + * @return: + * Value~1 if everything is OK. Value~0 gets returned when the paint + * object can not be retrieved or any other error occurs. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + FT_EXPORT( FT_Bool ) + FT_Get_Paint_Layers( FT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + + /************************************************************************** + * + * @function: + * FT_Get_Colorline_Stops + * + * @description: + * This is an interface to color gradient information in a 'COLR' v1 + * table in OpenType fonts to iteratively retrieve the gradient and + * solid fill information for colored glyph layers for a specified glyph + * ID. + * + * https://github.com/googlefonts/colr-gradients-spec + * + * @input: + * face :: + * A handle to the parent face object. + * + * @inout: + * iterator :: + * The retrieved @FT_ColorStopIterator, configured on an @FT_ColorLine, + * which in turn got retrieved via paint information in + * @FT_PaintLinearGradient or @FT_PaintRadialGradient. + * + * @output: + * color_stop :: + * Color index and alpha value for the retrieved color stop. + * + * @return: + * Value~1 if everything is OK. If there are no more color stops, + * value~0 gets returned. In case of an error, value~0 is returned + * also. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + FT_EXPORT( FT_Bool ) + FT_Get_Colorline_Stops( FT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + + /************************************************************************** + * + * @function: + * FT_Get_Paint + * + * @description: + * Access the details of a paint using an @FT_OpaquePaint opaque paint + * object, which internally stores the offset to the respective `Paint` + * object in the 'COLR' table. + * + * @input: + * face :: + * A handle to the parent face object. + * + * opaque_paint :: + * The opaque paint object for which the underlying @FT_COLR_Paint + * data is to be retrieved. + * + * @output: + * paint :: + * The specific @FT_COLR_Paint object containing information coming + * from one of the font's `Paint*` tables. + * + * @return: + * Value~1 if everything is OK. Value~0 if no details can be found for + * this paint or any other error occured. + * + * @since: + * 2.11 -- **currently experimental only!** There might be changes + * without retaining backward compatibility of both the API and ABI. + * + */ + FT_EXPORT( FT_Bool ) + FT_Get_Paint( FT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + /* */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType API for controlling driver modules (specification only). * - * Copyright (C) 2017-2020 by + * Copyright (C) 2017-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -53,10 +53,10 @@ * reasons. * * Available properties are @increase-x-height, @no-stem-darkening - * (experimental), @darkening-parameters (experimental), @warping - * (experimental), @glyph-to-script-map (experimental), @fallback-script - * (experimental), and @default-script (experimental), as documented in - * the @properties section. + * (experimental), @darkening-parameters (experimental), + * @glyph-to-script-map (experimental), @fallback-script (experimental), + * and @default-script (experimental), as documented in the @properties + * section. * */ @@ -84,15 +84,15 @@ * @properties section. * * - * **Hinting and antialiasing principles of the new engine** + * **Hinting and anti-aliasing principles of the new engine** * * The rasterizer is positioning horizontal features (e.g., ascender * height & x-height, or crossbars) on the pixel grid and minimizing the - * amount of antialiasing applied to them, while placing vertical + * amount of anti-aliasing applied to them, while placing vertical * features (vertical stems) on the pixel grid without hinting, thus * representing the stem position and weight accurately. Sometimes the * vertical stems may be only partially black. In this context, - * 'antialiasing' means that stems are not positioned exactly on pixel + * 'anti-aliasing' means that stems are not positioned exactly on pixel * borders, causing a fuzzy appearance. * * There are two principles behind this approach. @@ -108,7 +108,7 @@ * sizes are comparable to kerning values and thus would be noticeable * (and distracting) while reading if hinting were applied. * - * One of the reasons to not hint horizontally is antialiasing for LCD + * One of the reasons to not hint horizontally is anti-aliasing for LCD * screens: The pixel geometry of modern displays supplies three vertical * subpixels as the eye moves horizontally across each visible pixel. On * devices where we can be certain this characteristic is present a @@ -116,7 +116,7 @@ * weight. In Western writing systems this turns out to be the more * critical direction anyway; the weights and spacing of vertical stems * (see above) are central to Armenian, Cyrillic, Greek, and Latin type - * designs. Even when the rasterizer uses greyscale antialiasing instead + * designs. Even when the rasterizer uses greyscale anti-aliasing instead * of color (a necessary compromise when one doesn't know the screen * characteristics), the unhinted vertical features preserve the design's * weight and spacing much better than aliased type would. @@ -212,16 +212,14 @@ * @description: * While FreeType's TrueType driver doesn't expose API functions by * itself, it is possible to control its behaviour with @FT_Property_Set - * and @FT_Property_Get. The following lists the available properties - * together with the necessary macros and structures. - * - * The TrueType driver's module name is 'truetype'. + * and @FT_Property_Get. * - * A single property @interpreter-version is available, as documented in - * the @properties section. + * The TrueType driver's module name is 'truetype'; a single property + * @interpreter-version is available, as documented in the @properties + * section. * - * We start with a list of definitions, kindly provided by Greg - * Hitchcock. + * To help understand the differences between interpreter versions, we + * introduce a list of definitions, kindly provided by Greg Hitchcock. * * _Bi-Level Rendering_ * @@ -303,6 +301,31 @@ /************************************************************************** * * @section: + * ot_svg_driver + * + * @title: + * The SVG driver + * + * @abstract: + * Controlling the external rendering of OT-SVG glyphs. + * + * @description: + * By default, FreeType can only load the 'SVG~' table of OpenType fonts + * if configuration macro `FT_CONFIG_OPTION_SVG` is defined. To make it + * render SVG glyphs, an external SVG rendering library is needed. All + * details on the interface between FreeType and the external library + * via function hooks can be found in section @svg_fonts. + * + * The OT-SVG driver's module name is 'ot-svg'; it supports a single + * property called @svg-hooks, documented below in the @properties + * section. + * + */ + + + /************************************************************************** + * + * @section: * properties * * @title: @@ -362,12 +385,8 @@ * The same holds for the Type~1 and CID modules if compiled with * `T1_CONFIG_OPTION_OLD_ENGINE`. * - * For the 'cff' module, the default engine is 'freetype' if - * `CFF_CONFIG_OPTION_OLD_ENGINE` is defined, and 'adobe' otherwise. - * - * For both the 'type1' and 't1cid' modules, the default engine is - * 'freetype' if `T1_CONFIG_OPTION_OLD_ENGINE` is defined, and 'adobe' - * otherwise. + * For the 'cff' module, the default engine is 'adobe'. For both the + * 'type1' and 't1cid' modules, the default engine is 'adobe', too. * * @note: * This property can be used with @FT_Property_Get also. @@ -805,6 +824,40 @@ /************************************************************************** * * @property: + * svg-hooks + * + * @description: + * Set up the interface between FreeType and an extern SVG rendering + * library like 'librsvg'. All details on the function hooks can be + * found in section @svg_fonts. + * + * @example: + * The following example code expects that the four hook functions + * `svg_*` are defined elsewhere. Error handling is omitted, too. + * + * ``` + * FT_Library library; + * SVG_RendererHooks hooks = { + * (SVG_Lib_Init_Func)svg_init, + * (SVG_Lib_Free_Func)svg_free, + * (SVG_Lib_Render_Func)svg_render, + * (SVG_Lib_Preset_Slot_Func)svg_preset_slot }; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "ot-svg", + * "svg-hooks", &hooks ); + * ``` + * + * @since: + * 2.12 + */ + + + /************************************************************************** + * + * @property: * glyph-to-script-map * * @description: @@ -1166,48 +1219,18 @@ * warping * * @description: - * **Experimental only** + * **Obsolete** * - * If FreeType gets compiled with option `AF_CONFIG_OPTION_USE_WARPER` to - * activate the warp hinting code in the auto-hinter, this property - * switches warping on and off. + * This property was always experimental and probably never worked + * correctly. It was entirely removed from the FreeType~2 sources. This + * entry is only here for historical reference. * - * Warping only works in 'normal' auto-hinting mode replacing it. The - * idea of the code is to slightly scale and shift a glyph along the + * Warping only worked in 'normal' auto-hinting mode replacing it. The + * idea of the code was to slightly scale and shift a glyph along the * non-hinted dimension (which is usually the horizontal axis) so that as - * much of its segments are aligned (more or less) to the grid. To find + * much of its segments were aligned (more or less) to the grid. To find * out a glyph's optimal scaling and shifting value, various parameter - * combinations are tried and scored. - * - * By default, warping is off. - * - * @note: - * This property can be used with @FT_Property_Get also. - * - * This property can be set via the `FREETYPE_PROPERTIES` environment - * variable (using values 1 and 0 for 'on' and 'off', respectively). - * - * The warping code can also change advance widths. Have a look at the - * `lsb_delta` and `rsb_delta` fields in the @FT_GlyphSlotRec structure - * for details on improving inter-glyph distances while rendering. - * - * Since warping is a global property of the auto-hinter it is best to - * change its value before rendering any face. Otherwise, you should - * reload all faces that get auto-hinted in 'normal' hinting mode. - * - * @example: - * This example shows how to switch on warping (omitting the error - * handling). - * - * ``` - * FT_Library library; - * FT_Bool warping = 1; - * - * - * FT_Init_FreeType( &library ); - * - * FT_Property_Set( library, "autofitter", "warping", &warping ); - * ``` + * combinations were tried and scored. * * @since: * 2.6 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType error codes (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -101,6 +101,8 @@ "too many hints" ) FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, "invalid pixel size" ) + FT_ERRORDEF_( Invalid_SVG_Document, 0x18, + "invalid SVG document" ) /* handle errors */ @@ -234,6 +236,8 @@ "found FDEF or IDEF opcode in glyf bytecode" ) FT_ERRORDEF_( Missing_Bitmap, 0x9D, "missing bitmap in strike" ) + FT_ERRORDEF_( Missing_SVG_Hooks, 0x9E, + "SVG hooks have not been set" ) /* CFF, CID, and Type 1 errors */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType error code handling (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -281,6 +281,8 @@ FT_EXPORT( const char* ) FT_Error_String( FT_Error error_code ); + /* */ + FT_END_HEADER diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Support functions for font formats. * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Access of TrueType's 'gasp' table (specification). * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -126,7 +126,7 @@ * * @description: * A handle to an object used to model a bitmap glyph image. This is a - * sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. + * 'sub-class' of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. */ typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; @@ -142,7 +142,7 @@ * * @fields: * root :: - * The root @FT_Glyph fields. + * The root fields of @FT_Glyph. * * left :: * The left-side bearing, i.e., the horizontal distance from the @@ -181,7 +181,7 @@ * * @description: * A handle to an object used to model an outline glyph image. This is a - * sub-class of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. + * 'sub-class' of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. */ typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; @@ -224,6 +224,92 @@ /************************************************************************** * + * @type: + * FT_SvgGlyph + * + * @description: + * A handle to an object used to model an SVG glyph. This is a + * 'sub-class' of @FT_Glyph, and a pointer to @FT_SvgGlyphRec. + * + * @since: + * 2.12 + */ + typedef struct FT_SvgGlyphRec_* FT_SvgGlyph; + + + /************************************************************************** + * + * @struct: + * FT_SvgGlyphRec + * + * @description: + * A structure used for OT-SVG glyphs. This is a 'sub-class' of + * @FT_GlyphRec. + * + * @fields: + * root :: + * The root @FT_GlyphRec fields. + * + * svg_document :: + * A pointer to the SVG document. + * + * svg_document_length :: + * The length of `svg_document`. + * + * glyph_index :: + * The index of the glyph to be rendered. + * + * metrics :: + * A metrics object storing the size information. + * + * units_per_EM :: + * The size of the EM square. + * + * start_glyph_id :: + * The first glyph ID in the glyph range covered by this document. + * + * end_glyph_id :: + * The last glyph ID in the glyph range covered by this document. + * + * transform :: + * A 2x2 transformation matrix to apply to the glyph while rendering + * it. + * + * delta :: + * Translation to apply to the glyph while rendering. + * + * @note: + * The Glyph Management API requires @FT_Glyph or its 'sub-class' to have + * all the information needed to completely define the glyph's rendering. + * Outline-based glyphs can directly apply transformations to the outline + * but this is not possible for an SVG document that hasn't been parsed. + * Therefore, the transformation is stored along with the document. In + * the absence of a 'ViewBox' or 'Width'/'Height' attribute, the size of + * the ViewPort should be assumed to be 'units_per_EM'. + */ + typedef struct FT_SvgGlyphRec_ + { + FT_GlyphRec root; + + FT_Byte* svg_document; + FT_ULong svg_document_length; + + FT_UInt glyph_index; + + FT_Size_Metrics metrics; + FT_UShort units_per_EM; + + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_Matrix transform; + FT_Vector delta; + + } FT_SvgGlyphRec; + + + /************************************************************************** + * * @function: * FT_New_Glyph * @@ -337,9 +423,9 @@ * vector. */ FT_EXPORT( FT_Error ) - FT_Glyph_Transform( FT_Glyph glyph, - FT_Matrix* matrix, - FT_Vector* delta ); + FT_Glyph_Transform( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); /************************************************************************** @@ -498,9 +584,9 @@ * The glyph image is translated with the `origin` vector before * rendering. * - * The first parameter is a pointer to an @FT_Glyph handle, that will be + * The first parameter is a pointer to an @FT_Glyph handle that will be * _replaced_ by this function (with newly allocated data). Typically, - * you would use (omitting error handling): + * you would do something like the following (omitting error handling). * * ``` * FT_Glyph glyph; @@ -517,7 +603,7 @@ * if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) * { * error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, - * 0, 1 ); + * 0, 1 ); * if ( error ) // `glyph' unchanged * ... * } @@ -532,7 +618,7 @@ * FT_Done_Glyph( glyph ); * ``` * - * Here is another example, again without error handling: + * Here is another example, again without error handling. * * ``` * FT_Glyph glyphs[MAX_GLYPHS] @@ -569,10 +655,10 @@ * ``` */ FT_EXPORT( FT_Error ) - FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, - FT_Render_Mode render_mode, - FT_Vector* origin, - FT_Bool destroy ); + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + const FT_Vector* origin, + FT_Bool destroy ); /************************************************************************** diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Gzip-compressed stream support. * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * FreeType glyph image formats and default raster interface * (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -28,11 +28,6 @@ #define FTIMAGE_H_ - /* STANDALONE_ is from ftgrays.c */ -#ifndef STANDALONE_ -#endif - - FT_BEGIN_HEADER @@ -201,6 +196,11 @@ #define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 #define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 + /* */ + + /* For debugging, the @FT_Pixel_Mode enumeration must stay in sync */ + /* with the `pixel_modes` array in file `ftobjs.c`. */ + /************************************************************************** * @@ -401,11 +401,11 @@ * information. * * FT_OUTLINE_OVERLAP :: - * This flag indicates that this outline contains overlapping contrours - * and the anti-aliased renderer should perform oversampling to - * mitigate possible artifacts. This flag should _not_ be set for - * well designed glyphs without overlaps because it quadruples the - * rendering time. + * [Since 2.10.3] This flag indicates that this outline contains + * overlapping contours and the anti-aliased renderer should perform + * oversampling to mitigate possible artifacts. This flag should _not_ + * be set for well designed glyphs without overlaps because it quadruples + * the rendering time. * * FT_OUTLINE_HIGH_PRECISION :: * This flag indicates that the scan-line converter should try to @@ -695,11 +695,13 @@ * to get a simple enumeration without assigning special numbers. */ #ifndef FT_IMAGE_TAG -#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ - value = ( ( (unsigned long)_x1 << 24 ) | \ - ( (unsigned long)_x2 << 16 ) | \ - ( (unsigned long)_x3 << 8 ) | \ - (unsigned long)_x4 ) + +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( FT_STATIC_BYTE_CAST( unsigned long, _x1 ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( unsigned long, _x2 ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( unsigned long, _x3 ) << 8 ) | \ + FT_STATIC_BYTE_CAST( unsigned long, _x4 ) ) + #endif /* FT_IMAGE_TAG */ @@ -739,6 +741,10 @@ * contours. Some Type~1 fonts, like those in the Hershey family, * contain glyphs in this format. These are described as @FT_Outline, * but FreeType isn't currently capable of rendering them correctly. + * + * FT_GLYPH_FORMAT_SVG :: + * [Since 2.12] The glyph is represented by an SVG document in the + * 'SVG~' table. */ typedef enum FT_Glyph_Format_ { @@ -747,7 +753,8 @@ FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ), FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ), FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ), - FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ) + FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_SVG, 'S', 'V', 'G', ' ' ) } FT_Glyph_Format; @@ -772,17 +779,6 @@ /*************************************************************************/ - /************************************************************************** - * - * A raster is a scan converter, in charge of rendering an outline into a - * bitmap. This section contains the public API for rasters. - * - * Note that in FreeType 2, all rasters are now encapsulated within - * specific modules called 'renderers'. See `ftrender.h` for more details - * on renderers. - * - */ - /************************************************************************** * @@ -796,16 +792,35 @@ * How vectorial outlines are converted into bitmaps and pixmaps. * * @description: - * This section contains technical definitions. + * A raster or a rasterizer is a scan converter in charge of producing a + * pixel coverage bitmap that can be used as an alpha channel when + * compositing a glyph with a background. FreeType comes with two + * rasterizers: bilevel `raster1` and anti-aliased `smooth` are two + * separate modules. They are usually called from the high-level + * @FT_Load_Glyph or @FT_Render_Glyph functions and produce the entire + * coverage bitmap at once, while staying largely invisible to users. + * + * Instead of working with complete coverage bitmaps, it is also possible + * to intercept consecutive pixel runs on the same scanline with the same + * coverage, called _spans_, and process them individually. Only the + * `smooth` rasterizer permits this when calling @FT_Outline_Render with + * @FT_Raster_Params as described below. + * + * Working with either complete bitmaps or spans it is important to think + * of them as colorless coverage objects suitable as alpha channels to + * blend arbitrary colors with a background. For best results, it is + * recommended to use gamma correction, too. + * + * This section also describes the public API needed to set up alternative + * @FT_Renderer modules. * * @order: - * FT_Raster * FT_Span * FT_SpanFunc - * * FT_Raster_Params * FT_RASTER_FLAG_XXX * + * FT_Raster * FT_Raster_NewFunc * FT_Raster_DoneFunc * FT_Raster_ResetFunc @@ -818,24 +833,12 @@ /************************************************************************** * - * @type: - * FT_Raster - * - * @description: - * An opaque handle (pointer) to a raster object. Each object can be - * used independently to convert an outline into a bitmap or pixmap. - */ - typedef struct FT_RasterRec_* FT_Raster; - - - /************************************************************************** - * * @struct: * FT_Span * * @description: - * A structure used to model a single span of gray pixels when rendering - * an anti-aliased bitmap. + * A structure to model a single span of consecutive pixels when + * rendering an anti-aliased bitmap. * * @fields: * x :: @@ -852,8 +855,8 @@ * This structure is used by the span drawing callback type named * @FT_SpanFunc that takes the y~coordinate of the span as a parameter. * - * The coverage value is always between 0 and 255. If you want less gray - * values, the callback function has to reduce them. + * The anti-aliased rasterizer produces coverage values from 0 to 255, + * this is, from completely transparent to completely opaque. */ typedef struct FT_Span_ { @@ -871,8 +874,8 @@ * * @description: * A function used as a call-back by the anti-aliased renderer in order - * to let client applications draw themselves the gray pixel spans on - * each scan line. + * to let client applications draw themselves the pixel spans on each + * scan line. * * @input: * y :: @@ -888,11 +891,12 @@ * User-supplied data that is passed to the callback. * * @note: - * This callback allows client applications to directly render the gray - * spans of the anti-aliased bitmap to any kind of surfaces. + * This callback allows client applications to directly render the spans + * of the anti-aliased bitmap to any kind of surfaces. * * This can be used to write anti-aliased outlines directly to a given - * background bitmap, and even perform translucency. + * background bitmap using alpha compositing. It can also be used for + * oversampling and averaging. */ typedef void (*FT_SpanFunc)( int y, @@ -962,11 +966,17 @@ * will be clipped to a box specified in the `clip_box` field of the * @FT_Raster_Params structure. Otherwise, the `clip_box` is * effectively set to the bounding box and all spans are generated. + * + * FT_RASTER_FLAG_SDF :: + * This flag is set to indicate that a signed distance field glyph + * image should be generated. This is only used while rendering with + * the @FT_RENDER_MODE_SDF render mode. */ #define FT_RASTER_FLAG_DEFAULT 0x0 #define FT_RASTER_FLAG_AA 0x1 #define FT_RASTER_FLAG_DIRECT 0x2 #define FT_RASTER_FLAG_CLIP 0x4 +#define FT_RASTER_FLAG_SDF 0x8 /* these constants are deprecated; use the corresponding */ /* `FT_RASTER_FLAG_XXX` values instead */ @@ -1048,6 +1058,23 @@ /************************************************************************** + * + * @type: + * FT_Raster + * + * @description: + * An opaque handle (pointer) to a raster object. Each object can be + * used independently to convert an outline into a bitmap or pixmap. + * + * @note: + * In FreeType 2, all rasters are now encapsulated within specific + * @FT_Renderer modules and only used in their context. + * + */ + typedef struct FT_RasterRec_* FT_Raster; + + + /************************************************************************** * * @functype: * FT_Raster_NewFunc diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType incremental loading (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -213,9 +213,14 @@ * * @description: * A function used to retrieve the basic metrics of a given glyph index - * before accessing its data. This is necessary because, in certain - * formats like TrueType, the metrics are stored in a different place - * from the glyph images proper. + * before accessing its data. This allows for handling font types such + * as PCL~XL Format~1, Class~2 downloaded TrueType fonts, where the glyph + * metrics (`hmtx` and `vmtx` tables) are permitted to be omitted from + * the font, and the relevant metrics included in the header of the glyph + * outline data. Importantly, this is not intended to allow custom glyph + * metrics (for example, Postscript Metrics dictionaries), because that + * conflicts with the requirements of outline hinting. Such custom + * metrics must be handled separately, by the calling application. * * @input: * incremental :: @@ -235,7 +240,7 @@ * * @output: * ametrics :: - * The replacement glyph metrics in font units. + * The glyph metrics in font units. * */ typedef FT_Error @@ -264,7 +269,7 @@ * * get_glyph_metrics :: * The function to get glyph metrics. May be null if the font does not - * provide overriding glyph metrics. + * require it. * */ typedef struct FT_Incremental_FuncsRec_ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * FreeType API for color filtering of subpixel bitmap glyphs * (specification). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -55,13 +55,12 @@ * ClearType-style LCD rendering exploits the color-striped structure of * LCD pixels, increasing the available resolution in the direction of * the stripe (usually horizontal RGB) by a factor of~3. Using the - * subpixels coverages unfiltered can create severe color fringes + * subpixel coverages unfiltered can create severe color fringes * especially when rendering thin features. Indeed, to produce * black-on-white text, the nearby color subpixels must be dimmed - * equally. - * - * A good 5-tap FIR filter should be applied to subpixel coverages - * regardless of pixel boundaries and should have these properties: + * evenly. Therefore, an equalizing 5-tap FIR filter should be applied + * to subpixel coverages regardless of pixel boundaries and should have + * these properties: * * 1. It should be symmetrical, like {~a, b, c, b, a~}, to avoid * any shifts in appearance. @@ -84,7 +83,7 @@ * Harmony LCD rendering is suitable to panels with any regular subpixel * structure, not just monitors with 3 color striped subpixels, as long * as the color subpixels have fixed positions relative to the pixel - * center. In this case, each color channel is then rendered separately + * center. In this case, each color channel can be rendered separately * after shifting the outline opposite to the subpixel shift so that the * coverage maps are aligned. This method is immune to color fringes * because the shifts do not change integral coverage. @@ -101,9 +100,9 @@ * clockwise. Harmony with default LCD geometry is equivalent to * ClearType with light filter. * - * As a result of ClearType filtering or Harmony rendering, the - * dimensions of LCD bitmaps can be either wider or taller than the - * dimensions of the corresponding outline with regard to the pixel grid. + * As a result of ClearType filtering or Harmony shifts, the resulting + * dimensions of LCD bitmaps can be slightly wider or taller than the + * dimensions the original outline with regard to the pixel grid. * For example, for @FT_RENDER_MODE_LCD, the filter adds 2~subpixels to * the left, and 2~subpixels to the right. The bitmap offset values are * adjusted accordingly, so clients shouldn't need to modify their layout diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Generic list support for FreeType (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,184 @@ +/**************************************************************************** + * + * ftlogging.h + * + * Additional debugging APIs. + * + * Copyright (C) 2020-2022 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FTLOGGING_H_ +#define FTLOGGING_H_ + + +#include +#include FT_CONFIG_CONFIG_H + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * debugging_apis + * + * @title: + * External Debugging APIs + * + * @abstract: + * Public APIs to control the `FT_DEBUG_LOGGING` macro. + * + * @description: + * This section contains the declarations of public functions that + * enables fine control of what the `FT_DEBUG_LOGGING` macro outputs. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Trace_Set_Level + * + * @description: + * Change the levels of tracing components of FreeType at run time. + * + * @input: + * tracing_level :: + * New tracing value. + * + * @example: + * The following call makes FreeType trace everything but the 'memory' + * component. + * + * ``` + * FT_Trace_Set_Level( "any:7 memory:0 ); + * ``` + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Trace_Set_Level( const char* tracing_level ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Set_Default_Level + * + * @description: + * Reset tracing value of FreeType's components to the default value + * (i.e., to the value of the `FT2_DEBUG` environment value or to NULL + * if `FT2_DEBUG` is not set). + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Trace_Set_Default_Level( void ); + + + /************************************************************************** + * + * @functype: + * FT_Custom_Log_Handler + * + * @description: + * A function typedef that is used to handle the logging of tracing and + * debug messages on a file system. + * + * @input: + * ft_component :: + * The name of `FT_COMPONENT` from which the current debug or error + * message is produced. + * + * fmt :: + * Actual debug or tracing message. + * + * args:: + * Arguments of debug or tracing messages. + * + * @since: + * 2.11 + * + */ + typedef void + (*FT_Custom_Log_Handler)( const char* ft_component, + const char* fmt, + va_list args ); + + + /************************************************************************** + * + * @function: + * FT_Set_Log_Handler + * + * @description: + * A function to set a custom log handler. + * + * @input: + * handler :: + * New logging function. + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ); + + + /************************************************************************** + * + * @function: + * FT_Set_Default_Log_Handler + * + * @description: + * A function to undo the effect of @FT_Set_Log_Handler, resetting the + * log handler to FreeType's built-in version. + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Set_Default_Log_Handler( void ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLOGGING_H_ */ + + +/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Additional Mac-specific API. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType Multiple Master font interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -47,6 +47,9 @@ * MM fonts, others will work with all three types. They are similar * enough that a consistent interface makes sense. * + * For Adobe MM fonts, macro @FT_IS_SFNT returns false. For GX and + * OpenType variation fonts, it returns true. + * */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType modules public interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -45,10 +45,12 @@ * * @description: * The definitions below are used to manage modules within FreeType. - * Modules can be added, upgraded, and removed at runtime. Additionally, - * some module properties can be controlled also. + * Internal and external modules can be added, upgraded, and removed at + * runtime. For example, an alternative renderer or proprietary font + * driver can be registered and prioritized. Additionally, some module + * properties can also be controlled. * - * Here is a list of possible values of the `module_name` field in the + * Here is a list of existing values of the `module_name` field in the * @FT_Module_Class structure. * * ``` @@ -86,6 +88,7 @@ * FT_Remove_Module * FT_Add_Default_Modules * + * FT_FACE_DRIVER_NAME * FT_Property_Set * FT_Property_Get * FT_Set_Default_Properties @@ -330,6 +333,27 @@ /************************************************************************** * + * @macro: + * FT_FACE_DRIVER_NAME + * + * @description: + * A macro that retrieves the name of a font driver from a face object. + * + * @note: + * The font driver name is a valid `module_name` for @FT_Property_Set + * and @FT_Property_Get. This is not the same as @FT_Get_Font_Format. + * + * @since: + * 2.11 + * + */ +#define FT_FACE_DRIVER_NAME( face ) \ + ( ( *FT_REINTERPRET_CAST( FT_Module_Class**, \ + ( face )->driver ) )->module_name ) + + + /************************************************************************** + * * @function: * FT_Property_Set * @@ -485,8 +509,7 @@ * * ``` * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ - * cff:no-stem-darkening=0 \ - * autofitter:warping=1 + * cff:no-stem-darkening=0 * ``` * * @inout: diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType module error offsets (specification). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -171,6 +171,7 @@ FT_MODERRDEF( Type42, 0x1400, "Type 42 module" ) FT_MODERRDEF( Winfonts, 0x1500, "Windows FON/FNT module" ) FT_MODERRDEF( GXvalid, 0x1600, "GX validation module" ) + FT_MODERRDEF( Sdf, 0x1700, "Signed distance field raster module" ) #ifdef FT_MODERR_END_LIST diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Support for the FT_Outline type used to store glyph shapes of * most scalable font formats (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -109,11 +109,13 @@ * FreeType error code. 0~means success. * * @note: - * A contour that contains a single point only is represented by a 'move - * to' operation followed by 'line to' to the same point. In most cases, - * it is best to filter this out before using the outline for stroking - * purposes (otherwise it would result in a visible dot when round caps - * are used). + * Degenerate contours, segments, and Bezier arcs may be reported. In + * most cases, it is best to filter these out before using the outline + * for stroking or other path modification purposes (which may cause + * degenerate segments to become non-degenrate and visible, like when + * stroke caps are used or the path is otherwise outset). Some glyph + * outlines may contain deliberate degenerate single points for mark + * attachement. * * Similarly, the function returns success for an empty outline also * (doing nothing, this is, not calling any emitter); if necessary, you diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType API for possible FT_Parameter tags (specification only). * - * Copyright (C) 2017-2020 by + * Copyright (C) 2017-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -113,6 +113,21 @@ /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_IGNORE_SBIX + * + * @description: + * A tag for @FT_Parameter to make @FT_Open_Face ignore an 'sbix' table + * while loading a font. Use this if @FT_FACE_FLAG_SBIX is set and you + * want to access the outline glyphs in the font. + * + */ +#define FT_PARAM_TAG_IGNORE_SBIX \ + FT_MAKE_TAG( 'i', 's', 'b', 'x' ) + + + /************************************************************************** * * @enum: * FT_PARAM_TAG_LCD_FILTER_WEIGHTS diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType renderer modules public interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType size objects management (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h 2022-07-14 08:05:38.000000000 +0000 @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType path stroker (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * FreeType synthesizing code for emboldening and slanting * (specification). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType low-level system interface definition (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (specification). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType simple types definitions (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -413,7 +413,7 @@ typedef struct FT_Data_ { const FT_Byte* pointer; - FT_Int length; + FT_UInt length; } FT_Data; @@ -479,18 +479,17 @@ * * @description: * This macro converts four-letter tags that are used to label TrueType - * tables into an unsigned long, to be used within FreeType. + * tables into an `FT_Tag` type, to be used within FreeType. * * @note: * The produced values **must** be 32-bit integers. Don't redefine this * macro. */ -#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ - (FT_Tag) \ - ( ( (FT_ULong)_x1 << 24 ) | \ - ( (FT_ULong)_x2 << 16 ) | \ - ( (FT_ULong)_x3 << 8 ) | \ - (FT_ULong)_x4 ) +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( FT_STATIC_BYTE_CAST( FT_Tag, _x1 ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( FT_Tag, _x2 ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( FT_Tag, _x3 ) << 8 ) | \ + FT_STATIC_BYTE_CAST( FT_Tag, _x4 ) ) /*************************************************************************/ @@ -588,7 +587,7 @@ #define FT_IS_EMPTY( list ) ( (list).head == 0 ) -#define FT_BOOL( x ) ( (FT_Bool)( (x) != 0 ) ) +#define FT_BOOL( x ) FT_STATIC_CAST( FT_Bool, (x) != 0 ) /* concatenate C tokens */ #define FT_ERR_XCAT( x, y ) x ## y diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level 'autohint' module-specific interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Basic OpenType/CFF object type definitions (specification). * - * Copyright (C) 2017-2020 by + * Copyright (C) 2017-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Basic OpenType/CFF type definitions and interface (specification * only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Compiler-specific macro definitions used internally by FreeType. * - * Copyright (C) 2020 by + * Copyright (C) 2020-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -71,12 +71,18 @@ */ #define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT -#ifdef _WIN64 +#ifdef __UINTPTR_TYPE__ + /* + * GCC and Clang both provide a `__UINTPTR_TYPE__` that can be used to + * avoid a dependency on `stdint.h`. + */ +# define FT_UINT_TO_POINTER( x ) (void *)(__UINTPTR_TYPE__)(x) +#elif defined( _WIN64 ) /* only 64bit Windows uses the LLP64 data model, i.e., */ /* 32-bit integers, 64-bit pointers. */ -#define FT_UINT_TO_POINTER( x ) (void *)(unsigned __int64)(x) +# define FT_UINT_TO_POINTER( x ) (void *)(unsigned __int64)(x) #else -#define FT_UINT_TO_POINTER( x ) (void *)(unsigned long)(x) +# define FT_UINT_TO_POINTER( x ) (void *)(unsigned long)(x) #endif /* @@ -216,79 +222,93 @@ #define FT_EXPORT_VAR( x ) FT_FUNCTION_DECLARATION( x ) #endif - /* When compiling FreeType as a DLL or DSO with hidden visibility, */ - /* some systems/compilers need a special attribute in front OR after */ - /* the return type of function declarations. */ - /* */ - /* Two macros are used within the FreeType source code to define */ - /* exported library functions: `FT_EXPORT` and `FT_EXPORT_DEF`. */ - /* */ - /* - `FT_EXPORT( return_type )` */ - /* */ - /* is used in a function declaration, as in */ - /* */ - /* ``` */ - /* FT_EXPORT( FT_Error ) */ - /* FT_Init_FreeType( FT_Library* alibrary ); */ - /* ``` */ - /* */ - /* - `FT_EXPORT_DEF( return_type )` */ - /* */ - /* is used in a function definition, as in */ - /* */ - /* ``` */ - /* FT_EXPORT_DEF( FT_Error ) */ - /* FT_Init_FreeType( FT_Library* alibrary ) */ - /* { */ - /* ... some code ... */ - /* return FT_Err_Ok; */ - /* } */ - /* ``` */ - /* */ - /* You can provide your own implementation of `FT_EXPORT` and */ - /* `FT_EXPORT_DEF` here if you want. */ - /* */ - /* To export a variable, use `FT_EXPORT_VAR`. */ - /* */ + /* + * When compiling FreeType as a DLL or DSO with hidden visibility, + * some systems/compilers need a special attribute in front OR after + * the return type of function declarations. + * + * Two macros are used within the FreeType source code to define + * exported library functions: `FT_EXPORT` and `FT_EXPORT_DEF`. + * + * - `FT_EXPORT( return_type )` + * + * is used in a function declaration, as in + * + * ``` + * FT_EXPORT( FT_Error ) + * FT_Init_FreeType( FT_Library* alibrary ); + * ``` + * + * - `FT_EXPORT_DEF( return_type )` + * + * is used in a function definition, as in + * + * ``` + * FT_EXPORT_DEF( FT_Error ) + * FT_Init_FreeType( FT_Library* alibrary ) + * { + * ... some code ... + * return FT_Err_Ok; + * } + * ``` + * + * You can provide your own implementation of `FT_EXPORT` and + * `FT_EXPORT_DEF` here if you want. + * + * To export a variable, use `FT_EXPORT_VAR`. + */ /* See `freetype/config/compiler_macros.h` for the `FT_EXPORT` definition */ #define FT_EXPORT_DEF( x ) FT_FUNCTION_DEFINITION( x ) - /* The following macros are needed to compile the library with a */ - /* C++ compiler and with 16bit compilers. */ - /* */ - - /* This is special. Within C++, you must specify `extern "C"` for */ - /* functions which are used via function pointers, and you also */ - /* must do that for structures which contain function pointers to */ - /* assure C linkage -- it's not possible to have (local) anonymous */ - /* functions which are accessed by (global) function pointers. */ - /* */ - /* */ - /* FT_CALLBACK_DEF is used to _define_ a callback function, */ - /* located in the same source code file as the structure that uses */ - /* it. */ - /* */ - /* FT_BASE_CALLBACK and FT_BASE_CALLBACK_DEF are used to declare */ - /* and define a callback function, respectively, in a similar way */ - /* as FT_BASE and FT_BASE_DEF work. */ - /* */ - /* FT_CALLBACK_TABLE is used to _declare_ a constant variable that */ - /* contains pointers to callback functions. */ - /* */ - /* FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable */ - /* that contains pointers to callback functions. */ - /* */ - /* */ - /* Some 16bit compilers have to redefine these macros to insert */ - /* the infamous `_cdecl` or `__fastcall` declarations. */ - /* */ + /* + * The following macros are needed to compile the library with a + * C++ compiler and with 16bit compilers. + */ + + /* + * This is special. Within C++, you must specify `extern "C"` for + * functions which are used via function pointers, and you also + * must do that for structures which contain function pointers to + * assure C linkage -- it's not possible to have (local) anonymous + * functions which are accessed by (global) function pointers. + * + * + * FT_CALLBACK_DEF is used to _define_ a callback function, + * located in the same source code file as the structure that uses + * it. FT_COMPARE_DEF, in addition, ensures the `cdecl` calling + * convention on x86, required by the C library function `qsort`. + * + * FT_BASE_CALLBACK and FT_BASE_CALLBACK_DEF are used to declare + * and define a callback function, respectively, in a similar way + * as FT_BASE and FT_BASE_DEF work. + * + * FT_CALLBACK_TABLE is used to _declare_ a constant variable that + * contains pointers to callback functions. + * + * FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable + * that contains pointers to callback functions. + * + * + * Some 16bit compilers have to redefine these macros to insert + * the infamous `_cdecl` or `__fastcall` declarations. + */ #ifdef __cplusplus #define FT_CALLBACK_DEF( x ) extern "C" x #else #define FT_CALLBACK_DEF( x ) static x #endif +#if defined( __GNUC__ ) && defined( __i386__ ) +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __attribute__(( cdecl )) +#elif defined( _MSC_VER ) && defined( _M_IX86 ) +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __cdecl +#elif defined( __WATCOMC__ ) && __WATCOMC__ >= 1240 +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __watcall +#else +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) +#endif + #define FT_BASE_CALLBACK( x ) FT_FUNCTION_DECLARATION( x ) #define FT_BASE_CALLBACK_DEF( x ) FT_FUNCTION_DEFINITION( x ) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Arithmetic computations (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -359,8 +359,8 @@ #ifndef FT_CONFIG_OPTION_NO_ASSEMBLER -#if defined( __GNUC__ ) && \ - ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) ) +#if defined( __clang__ ) || ( defined( __GNUC__ ) && \ + ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) ) ) #if FT_SIZEOF_INT == 4 @@ -370,12 +370,25 @@ #define FT_MSB( x ) ( 31 - __builtin_clzl( x ) ) -#endif /* __GNUC__ */ +#endif +#elif defined( _MSC_VER ) && _MSC_VER >= 1400 -#elif defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) +#if defined( _WIN32_WCE ) -#if FT_SIZEOF_INT == 4 +#include +#pragma intrinsic( _CountLeadingZeros ) + +#define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) + +#elif defined( _M_ARM64 ) || defined( _M_ARM ) + +#include +#pragma intrinsic( _CountLeadingZeros ) + +#define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) + +#elif defined( _M_IX86 ) || defined( _M_AMD64 ) || defined( _M_IA64 ) #include #pragma intrinsic( _BitScanReverse ) @@ -391,15 +404,40 @@ return (FT_Int32)where; } -#define FT_MSB( x ) ( FT_MSB_i386( x ) ) +#define FT_MSB( x ) FT_MSB_i386( x ) #endif -#endif /* _MSC_VER */ +#elif defined( __WATCOMC__ ) && defined( __386__ ) + extern __inline FT_Int32 + FT_MSB_i386( FT_UInt32 x ); + +#pragma aux FT_MSB_i386 = \ + "bsr eax, eax" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; + +#define FT_MSB( x ) FT_MSB_i386( x ) + +#elif defined( __DECC ) || defined( __DECCXX ) + +#include + +#define FT_MSB( x ) (FT_Int)( 63 - _leadz( x ) ) + +#elif defined( _CRAYC ) + +#include + +#define FT_MSB( x ) (FT_Int)( 31 - _leadz32( x ) ) + +#endif /* FT_MSB macro definitions */ #endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + #ifndef FT_MSB FT_BASE( FT_Int ) @@ -487,7 +525,7 @@ #define NEG_INT32( a ) \ (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) ) -#ifdef FT_LONG64 +#ifdef FT_INT64 #define ADD_INT64( a, b ) \ (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) ) @@ -498,7 +536,7 @@ #define NEG_INT64( a ) \ (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) ) -#endif /* FT_LONG64 */ +#endif /* FT_INT64 */ FT_END_HEADER diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Debugging and logging component (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -31,9 +31,24 @@ #include "compiler-macros.h" +#ifdef FT_DEBUG_LOGGING +#define DLG_STATIC +#include +#include + +#include +#endif /* FT_DEBUG_LOGGING */ + FT_BEGIN_HEADER + /* force the definition of FT_DEBUG_LEVEL_TRACE if FT_DEBUG_LOGGING is */ + /* already defined. */ + /* */ +#ifdef FT_DEBUG_LOGGING +#undef FT_DEBUG_LEVEL_TRACE +#define FT_DEBUG_LEVEL_TRACE +#endif /* force the definition of FT_DEBUG_LEVEL_ERROR if FT_DEBUG_LEVEL_TRACE */ /* is already defined; this simplifies the following #ifdefs */ @@ -82,21 +97,67 @@ * Each component must define the macro FT_COMPONENT to a valid FT_Trace * value before using any TRACE macro. * + * To get consistent logging output, there should be no newline character + * (i.e., '\n') or a single trailing one in the message string of + * `FT_TRACEx` and `FT_ERROR`. */ -#ifdef FT_DEBUG_LEVEL_TRACE - /* we need two macros here to make cpp expand `FT_COMPONENT' */ -#define FT_TRACE_COMP( x ) FT_TRACE_COMP_( x ) -#define FT_TRACE_COMP_( x ) trace_ ## x + /************************************************************************* + * + * If FT_DEBUG_LOGGING is enabled, tracing messages are sent to dlg's API. + * If FT_DEBUG_LOGGING is disabled, tracing messages are sent to + * `FT_Message` (defined in ftdebug.c). + */ +#ifdef FT_DEBUG_LOGGING + + /* we need two macros to convert the names of `FT_COMPONENT` to a string */ +#define FT_LOGGING_TAG( x ) FT_LOGGING_TAG_( x ) +#define FT_LOGGING_TAG_( x ) #x -#define FT_TRACE( level, varformat ) \ + /* we need two macros to convert the component and the trace level */ + /* to a string that combines them */ +#define FT_LOGGING_TAGX( x, y ) FT_LOGGING_TAGX_( x, y ) +#define FT_LOGGING_TAGX_( x, y ) #x ":" #y + + +#define FT_LOG( level, varformat ) \ + do \ + { \ + const char* dlg_tag = FT_LOGGING_TAGX( FT_COMPONENT, level ); \ + \ + \ + ft_add_tag( dlg_tag ); \ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ + { \ + if ( custom_output_handler != NULL ) \ + FT_Logging_Callback varformat; \ + else \ + dlg_trace varformat; \ + } \ + ft_remove_tag( dlg_tag ); \ + } while( 0 ) + +#else /* !FT_DEBUG_LOGGING */ + +#define FT_LOG( level, varformat ) \ do \ { \ if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ FT_Message varformat; \ } while ( 0 ) +#endif /* !FT_DEBUG_LOGGING */ + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* we need two macros here to make cpp expand `FT_COMPONENT' */ +#define FT_TRACE_COMP( x ) FT_TRACE_COMP_( x ) +#define FT_TRACE_COMP_( x ) trace_ ## x + +#define FT_TRACE( level, varformat ) FT_LOG( level, varformat ) + #else /* !FT_DEBUG_LEVEL_TRACE */ #define FT_TRACE( level, varformat ) do { } while ( 0 ) /* nothing */ @@ -204,7 +265,32 @@ #ifdef FT_DEBUG_LEVEL_ERROR -#define FT_ERROR( varformat ) FT_Message varformat + /************************************************************************** + * + * If FT_DEBUG_LOGGING is enabled, error messages are sent to dlg's API. + * If FT_DEBUG_LOGGING is disabled, error messages are sent to `FT_Message` + * (defined in ftdebug.c). + * + */ +#ifdef FT_DEBUG_LOGGING + +#define FT_ERROR( varformat ) \ + do \ + { \ + const char* dlg_tag = FT_LOGGING_TAG( FT_COMPONENT ); \ + \ + \ + ft_add_tag( dlg_tag ); \ + dlg_trace varformat; \ + ft_remove_tag( dlg_tag ); \ + } while ( 0 ) + +#else /* !FT_DEBUG_LOGGING */ + +#define FT_ERROR( varformat ) FT_Message varformat + +#endif /* !FT_DEBUG_LOGGING */ + #else /* !FT_DEBUG_LEVEL_ERROR */ @@ -277,6 +363,77 @@ FT_BASE( void ) ft_debug_init( void ); + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * 'dlg' uses output handlers to control how and where log messages are + * printed. Therefore we need to define a default output handler for + * FreeType. + */ + FT_BASE( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ); + + + /************************************************************************** + * + * 1. `ft_default_log_handler` stores the function pointer that is used + * internally by FreeType to print logs to a file. + * + * 2. `custom_output_handler` stores the function pointer to the callback + * function provided by the user. + * + * It is defined in `ftdebug.c`. + */ + extern dlg_handler ft_default_log_handler; + extern FT_Custom_Log_Handler custom_output_handler; + + + /************************************************************************** + * + * If FT_DEBUG_LOGGING macro is enabled, FreeType needs to initialize and + * un-initialize `FILE*`. + * + * These functions are defined in `ftdebug.c`. + */ + FT_BASE( void ) + ft_logging_init( void ); + + FT_BASE( void ) + ft_logging_deinit( void ); + + + /************************************************************************** + * + * For printing the name of `FT_COMPONENT` along with the actual log we + * need to add a tag with the name of `FT_COMPONENT`. + * + * These functions are defined in `ftdebug.c`. + */ + FT_BASE( void ) + ft_add_tag( const char* tag ); + + FT_BASE( void ) + ft_remove_tag( const char* tag ); + + + /************************************************************************** + * + * A function to print log data using a custom callback logging function + * (which is set using `FT_Set_Log_Handler`). + * + * This function is defined in `ftdebug.c`. + */ + FT_BASE( void ) + FT_Logging_Callback( const char* fmt, + ... ); + +#endif /* FT_DEBUG_LOGGING */ + + FT_END_HEADER #endif /* FTDEBUG_H_ */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType internal font driver interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType glyph loader (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, @@ -22,6 +22,7 @@ #include +#include "compiler-macros.h" FT_BEGIN_HEADER diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType memory management macros (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, @@ -344,14 +344,13 @@ #define FT_RENEW_ARRAY( ptr, curcnt, newcnt ) \ FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) -#define FT_QNEW( ptr ) \ - FT_MEM_SET_ERROR( FT_MEM_QNEW( ptr ) ) +#define FT_QNEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_QNEW( ptr ) ) -#define FT_QNEW_ARRAY( ptr, count ) \ - FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) +#define FT_QNEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_QNEW_ARRAY( ptr, count ) ) -#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ - FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) +#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_QRENEW_ARRAY( ptr, curcnt, newcnt ) ) FT_BASE( FT_Pointer ) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType private base classes (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -418,7 +418,8 @@ * initializing the glyph slot. */ -#define FT_GLYPH_OWN_BITMAP 0x1U +#define FT_GLYPH_OWN_BITMAP 0x1U +#define FT_GLYPH_OWN_GZIP_SVG 0x2U typedef struct FT_Slot_InternalRec_ { @@ -673,7 +674,7 @@ /* Set the metrics according to a size request. */ - FT_BASE( void ) + FT_BASE( FT_Error ) FT_Request_Metrics( FT_Face face, FT_Size_Request req ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Get and set properties of PostScript drivers (specification). * - * Copyright (C) 2017-2020 by + * Copyright (C) 2017-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (specification). * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * Masatake YAMATO and Redhat K.K. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType services (specification only). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Stream handling (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -196,9 +196,9 @@ FT_BYTE_U32( p, 2, 8 ) | \ FT_BYTE_U32( p, 3, 0 ) ) -#define FT_PEEK_OFF3( p ) FT_INT32( FT_BYTE_U32( p, 0, 16 ) | \ - FT_BYTE_U32( p, 1, 8 ) | \ - FT_BYTE_U32( p, 2, 0 ) ) +#define FT_PEEK_OFF3( p ) ( FT_INT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) ) >> 8 ) #define FT_PEEK_UOFF3( p ) FT_UINT32( FT_BYTE_U32( p, 0, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ @@ -220,9 +220,9 @@ FT_BYTE_U32( p, 1, 8 ) | \ FT_BYTE_U32( p, 0, 0 ) ) -#define FT_PEEK_OFF3_LE( p ) FT_INT32( FT_BYTE_U32( p, 2, 16 ) | \ - FT_BYTE_U32( p, 1, 8 ) | \ - FT_BYTE_U32( p, 0, 0 ) ) +#define FT_PEEK_OFF3_LE( p ) ( FT_INT32( FT_BYTE_U32( p, 2, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 0, 8 ) ) >> 8 ) #define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ @@ -305,11 +305,10 @@ #else #define FT_GET_MACRO( func, type ) ( (type)func( stream ) ) -#define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetChar, FT_Char ) -#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetChar, FT_Byte ) +#define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetByte, FT_Char ) +#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetByte, FT_Byte ) #define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_Short ) #define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UShort ) -#define FT_GET_OFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_Long ) #define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_ULong ) #define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Long ) #define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong ) @@ -333,11 +332,10 @@ * `FT_STREAM_POS'. They use the full machinery to check whether a read is * valid. */ -#define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Byte, var ) -#define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Char, var ) +#define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadByte, FT_Byte, var ) +#define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadByte, FT_Char, var ) #define FT_READ_SHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_Short, var ) #define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_UShort, var ) -#define FT_READ_OFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_Long, var ) #define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_ULong, var ) #define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_Long, var ) #define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_ULong, var ) @@ -457,8 +455,8 @@ /* read a byte from an entered frame */ - FT_BASE( FT_Char ) - FT_Stream_GetChar( FT_Stream stream ); + FT_BASE( FT_Byte ) + FT_Stream_GetByte( FT_Stream stream ); /* read a 16-bit big-endian unsigned integer from an entered frame */ FT_BASE( FT_UShort ) @@ -482,8 +480,8 @@ /* read a byte from a stream */ - FT_BASE( FT_Char ) - FT_Stream_ReadChar( FT_Stream stream, + FT_BASE( FT_Byte ) + FT_Stream_ReadByte( FT_Stream stream, FT_Error* error ); /* read a 16-bit big-endian unsigned integer from a stream */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Tracing handling (specification only). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,6 +18,11 @@ /* definitions of trace levels for FreeType 2 */ + /* the maximum string length (if the argument to `FT_TRACE_DEF` */ + /* gets used as a string) plus one charachter for ':' plus */ + /* another one for the trace level */ +#define FT_MAX_TRACE_LEVEL_LENGTH (9 + 1 + 1) + /* the first level must always be `trace_any' */ FT_TRACE_DEF( any ) @@ -38,12 +43,17 @@ FT_TRACE_DEF( mm ) /* MM interface (ftmm.c) */ FT_TRACE_DEF( psprops ) /* PS driver properties (ftpsprop.c) */ FT_TRACE_DEF( raccess ) /* resource fork accessor (ftrfork.c) */ +FT_TRACE_DEF( synth ) /* bold/slant synthesizer (ftsynth.c) */ + + /* rasterizers */ FT_TRACE_DEF( raster ) /* monochrome rasterizer (ftraster.c) */ FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */ -FT_TRACE_DEF( synth ) /* bold/slant synthesizer (ftsynth.c) */ - /* Cache sub-system */ -FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */ + /* ot-svg module */ +FT_TRACE_DEF( otsvg ) /* OT-SVG renderer (ftsvg.c) */ + + /* cache sub-system */ +FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */ /* SFNT driver components */ FT_TRACE_DEF( sfdriver ) /* SFNT font driver (sfdriver.c) */ @@ -54,6 +64,7 @@ FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */ FT_TRACE_DEF( ttcolr ) /* glyph layer table (ttcolr.c) */ FT_TRACE_DEF( ttcpal ) /* color palette table (ttcpal.c) */ +FT_TRACE_DEF( ttsvg ) /* OpenType SVG table (ttsvg.c) */ FT_TRACE_DEF( ttkern ) /* kerning handler (ttkern.c) */ FT_TRACE_DEF( ttload ) /* basic TrueType tables (ttload.c) */ FT_TRACE_DEF( ttmtx ) /* metrics-related tables (ttmtx.c) */ @@ -77,6 +88,7 @@ FT_TRACE_DEF( t1parse ) /* PostScript helper module `psaux' */ +FT_TRACE_DEF( afmparse ) FT_TRACE_DEF( cffdecode ) FT_TRACE_DEF( psconv ) FT_TRACE_DEF( psobjs ) @@ -151,8 +163,10 @@ FT_TRACE_DEF( afhints ) FT_TRACE_DEF( afmodule ) FT_TRACE_DEF( aflatin ) -FT_TRACE_DEF( aflatin2 ) FT_TRACE_DEF( afshaper ) -FT_TRACE_DEF( afwarp ) + + /* SDF components */ +FT_TRACE_DEF( sdf ) /* signed distance raster for outlines (ftsdf.c) */ +FT_TRACE_DEF( bsdf ) /* signed distance raster for bitmaps (ftbsdf.c) */ /* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType validation support (specification). * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Auxiliary functions and data structures related to PostScript fonts * (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h 2022-07-14 08:05:38.000000000 +0000 @@ -6,7 +6,7 @@ * recorders (specification only). These are used to support native * T1/T2 hints in the 'type1', 'cid', and 'cff' font drivers. * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType BDF services (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType CFF tables loader service (specification). * - * Copyright (C) 2017-2020 by + * Copyright (C) 2017-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType CID font services (specification). * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType font format service (specification only). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType glyph dictionary services (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType API for validating TrueTypeGX/AAT tables (specification). * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType Kerning service (specification). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType services for metrics variations (specification). * - * Copyright (C) 2016-2020 by + * Copyright (C) 2016-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType Multiple Masters and GX var services (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType OpenType validation service (specification). * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Internal PFR service functions (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType PostScript name services (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType property service (specification). * - * Copyright (C) 2012-2020 by + * Copyright (C) 2012-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType PostScript charmap service (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType PostScript info service (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType SFNT table loading service (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType TrueType/sfnt cmap extra information service. * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * Masatake YAMATO, Redhat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType TrueType engine query service (specification). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType TrueType glyph service. * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType Windows FNT/FONT service (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level 'sfnt' driver interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -314,6 +314,33 @@ /************************************************************************** * * @functype: + * TT_Load_Svg_Doc_Func + * + * @description: + * Scan the SVG document list to find the document containing the glyph + * that has the ID 'glyph*XXX*', where *XXX* is the value of + * `glyph_index` as a decimal integer. + * + * @inout: + * glyph :: + * The glyph slot from which pointers to the SVG document list is to be + * grabbed. The results are stored back in the slot. + * + * @input: + * glyph_index :: + * The index of the glyph that is to be looked up. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Load_Svg_Doc_Func)( FT_GlyphSlot glyph, + FT_UInt glyph_index ); + + + /************************************************************************** + * + * @functype: * TT_Set_SBit_Strike_Func * * @description: @@ -527,6 +554,170 @@ /************************************************************************** * * @functype: + * TT_Get_Color_Glyph_Paint_Func + * + * @description: + * Find the root @FT_OpaquePaint object for a given glyph ID. + * + * @input: + * face :: + * The target face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @output: + * paint :: + * The root @FT_OpaquePaint object. + * + * @return: + * Value~1 if everything is OK. If no color glyph is found, or the root + * paint could not be retrieved, value~0 gets returned. In case of an + * error, value~0 is returned also. + */ + typedef FT_Bool + ( *TT_Get_Color_Glyph_Paint_Func )( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Color_Glyph_ClipBox_Func + * + * @description: + * Search for a 'COLR' v1 clip box for the specified `base_glyph` and + * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information + * if one is found. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the clip box. + * + * @output: + * clip_box :: + * The clip box for the requested `base_glyph` if one is found. The + * clip box is computed taking scale and transformations configured on + * the @FT_Face into account. @FT_ClipBox contains @FT_Vector values + * in 26.6 format. + * + * @note: + * To retrieve the clip box in font units, reset scale to units-per-em + * and remove transforms configured using @FT_Set_Transform. + * + * @return: + * Value~1 if a ClipBox is found. If no clip box is found or an + * error occured, value~0 is returned. + */ + typedef FT_Bool + ( *TT_Get_Color_Glyph_ClipBox_Func )( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Paint_Layers_Func + * + * @description: + * Access the layers of a `PaintColrLayers` table. + * + * @input: + * face :: + * The target face object. + * + * @inout: + * iterator :: + * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which + * the layers are to be retrieved. The internal state of the iterator + * is incremented after one call to this function for retrieving one + * layer. + * + * @output: + * paint :: + * The root @FT_OpaquePaint object referencing the actual paint table. + * + * @return: + * Value~1 if everything is OK. Value~0 gets returned when the paint + * object can not be retrieved or any other error occurs. + */ + typedef FT_Bool + ( *TT_Get_Paint_Layers_Func )( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Colorline_Stops_Func + * + * @description: + * Get the gradient and solid fill information for a given glyph. + * + * @input: + * face :: + * The target face object. + * + * @inout: + * iterator :: + * An @FT_ColorStopIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * color_stop :: + * Color index and alpha value for the retrieved color stop. + * + * @return: + * Value~1 if everything is OK. If there are no more color stops, + * value~0 gets returned. In case of an error, value~0 is returned + * also. + */ + typedef FT_Bool + ( *TT_Get_Colorline_Stops_Func )( TT_Face face, + FT_ColorStop *color_stop, + FT_ColorStopIterator* iterator ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Paint_Func + * + * @description: + * Get the paint details for a given @FT_OpaquePaint object. + * + * @input: + * face :: + * The target face object. + * + * opaque_paint :: + * The @FT_OpaquePaint object. + * + * @output: + * paint :: + * An @FT_COLR_Paint object holding the details on `opaque_paint`. + * + * @return: + * Value~1 if everything is OK. Value~0 if no details can be found for + * this paint or any other error occured. + */ + typedef FT_Bool + ( *TT_Get_Paint_Func )( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint *paint ); + + + /************************************************************************** + * + * @functype: * TT_Blend_Colr_Func * * @description: @@ -709,73 +900,83 @@ */ typedef struct SFNT_Interface_ { - TT_Loader_GotoTableFunc goto_table; + TT_Loader_GotoTableFunc goto_table; - TT_Init_Face_Func init_face; - TT_Load_Face_Func load_face; - TT_Done_Face_Func done_face; - FT_Module_Requester get_interface; + TT_Init_Face_Func init_face; + TT_Load_Face_Func load_face; + TT_Done_Face_Func done_face; + FT_Module_Requester get_interface; - TT_Load_Any_Func load_any; + TT_Load_Any_Func load_any; /* these functions are called by `load_face' but they can also */ /* be called from external modules, if there is a need to do so */ - TT_Load_Table_Func load_head; - TT_Load_Metrics_Func load_hhea; - TT_Load_Table_Func load_cmap; - TT_Load_Table_Func load_maxp; - TT_Load_Table_Func load_os2; - TT_Load_Table_Func load_post; + TT_Load_Table_Func load_head; + TT_Load_Metrics_Func load_hhea; + TT_Load_Table_Func load_cmap; + TT_Load_Table_Func load_maxp; + TT_Load_Table_Func load_os2; + TT_Load_Table_Func load_post; - TT_Load_Table_Func load_name; - TT_Free_Table_Func free_name; + TT_Load_Table_Func load_name; + TT_Free_Table_Func free_name; /* this field was called `load_kerning' up to version 2.1.10 */ - TT_Load_Table_Func load_kern; + TT_Load_Table_Func load_kern; - TT_Load_Table_Func load_gasp; - TT_Load_Table_Func load_pclt; + TT_Load_Table_Func load_gasp; + TT_Load_Table_Func load_pclt; /* see `ttload.h'; this field was called `load_bitmap_header' up to */ /* version 2.1.10 */ - TT_Load_Table_Func load_bhed; + TT_Load_Table_Func load_bhed; - TT_Load_SBit_Image_Func load_sbit_image; + TT_Load_SBit_Image_Func load_sbit_image; /* see `ttpost.h' */ - TT_Get_PS_Name_Func get_psname; - TT_Free_Table_Func free_psnames; + TT_Get_PS_Name_Func get_psname; + TT_Free_Table_Func free_psnames; /* starting here, the structure differs from version 2.1.7 */ /* this field was introduced in version 2.1.8, named `get_psname' */ - TT_Face_GetKerningFunc get_kerning; + TT_Face_GetKerningFunc get_kerning; /* new elements introduced after version 2.1.10 */ /* load the font directory, i.e., the offset table and */ /* the table directory */ - TT_Load_Table_Func load_font_dir; - TT_Load_Metrics_Func load_hmtx; + TT_Load_Table_Func load_font_dir; + TT_Load_Metrics_Func load_hmtx; - TT_Load_Table_Func load_eblc; - TT_Free_Table_Func free_eblc; + TT_Load_Table_Func load_eblc; + TT_Free_Table_Func free_eblc; TT_Set_SBit_Strike_Func set_sbit_strike; TT_Load_Strike_Metrics_Func load_strike_metrics; - TT_Load_Table_Func load_cpal; - TT_Load_Table_Func load_colr; - TT_Free_Table_Func free_cpal; - TT_Free_Table_Func free_colr; - TT_Set_Palette_Func set_palette; - TT_Get_Colr_Layer_Func get_colr_layer; - TT_Blend_Colr_Func colr_blend; - - TT_Get_Metrics_Func get_metrics; - - TT_Get_Name_Func get_name; - TT_Get_Name_ID_Func get_name_id; + TT_Load_Table_Func load_cpal; + TT_Load_Table_Func load_colr; + TT_Free_Table_Func free_cpal; + TT_Free_Table_Func free_colr; + TT_Set_Palette_Func set_palette; + TT_Get_Colr_Layer_Func get_colr_layer; + TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint; + TT_Get_Color_Glyph_ClipBox_Func get_color_glyph_clipbox; + TT_Get_Paint_Layers_Func get_paint_layers; + TT_Get_Colorline_Stops_Func get_colorline_stops; + TT_Get_Paint_Func get_paint; + TT_Blend_Colr_Func colr_blend; + + TT_Get_Metrics_Func get_metrics; + + TT_Get_Name_Func get_name; + TT_Get_Name_ID_Func get_name_id; + + /* OpenType SVG Support */ + TT_Load_Table_Func load_svg; + TT_Free_Table_Func free_svg; + TT_Load_Svg_Doc_Func load_svg_doc; } SFNT_Interface; @@ -820,10 +1021,18 @@ free_colr_, \ set_palette_, \ get_colr_layer_, \ + get_colr_glyph_paint_, \ + get_color_glyph_clipbox, \ + get_paint_layers_, \ + get_colorline_stops_, \ + get_paint_, \ colr_blend_, \ get_metrics_, \ get_name_, \ - get_name_id_ ) \ + get_name_id_, \ + load_svg_, \ + free_svg_, \ + load_svg_doc_ ) \ static const SFNT_Interface class_ = \ { \ goto_table_, \ @@ -860,10 +1069,18 @@ free_colr_, \ set_palette_, \ get_colr_layer_, \ + get_colr_glyph_paint_, \ + get_color_glyph_clipbox, \ + get_paint_layers_, \ + get_colorline_stops_, \ + get_paint_, \ colr_blend_, \ get_metrics_, \ get_name_, \ - get_name_id_ \ + get_name_id_, \ + load_svg_, \ + free_svg_, \ + load_svg_doc_ \ }; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * svginterface.h + * + * Interface of ot-svg module (specification only). + * + * Copyright (C) 2022 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef SVGINTERFACE_H_ +#define SVGINTERFACE_H_ + +#include +#include + + +FT_BEGIN_HEADER + + typedef FT_Error + (*Preset_Bitmap_Func)( FT_Module module, + FT_GlyphSlot slot, + FT_Bool cache ); + + typedef struct SVG_Interface_ + { + Preset_Bitmap_Func preset_slot; + + } SVG_Interface; + + typedef SVG_Interface* SVG_Service; + +FT_END_HEADER + +#endif /* SVGINTERFACE_H_ */ + + +/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Basic Type1/Type2 type definitions and interface (specification * only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Basic SFNT/TrueType type definitions and interface (specification * only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -1372,7 +1372,7 @@ * * num_locations :: * The number of glyph locations in this TrueType file. This should be - * identical to the number of glyphs. Ignored for Type 2 fonts. + * one more than the number of glyphs. Ignored for Type 2 fonts. * * glyph_locations :: * An array of longs. These are offsets to glyph data within the @@ -1390,8 +1390,8 @@ * hdmx_record_size :: * The size of a single hdmx record. * - * hdmx_record_sizes :: - * An array holding the ppem sizes available in the 'hdmx' table. + * hdmx_records :: + * A array of pointers to the 'hdmx' table records sorted by ppem. * * sbit_table :: * A pointer to the font's embedded bitmap location table. @@ -1598,14 +1598,14 @@ FT_ULong horz_metrics_size; FT_ULong vert_metrics_size; - FT_ULong num_locations; /* in broken TTF, gid > 0xFFFF */ + FT_ULong num_locations; /* up to 0xFFFF + 1 */ FT_Byte* glyph_locations; FT_Byte* hdmx_table; FT_ULong hdmx_table_size; FT_UInt hdmx_record_count; FT_ULong hdmx_record_size; - FT_Byte* hdmx_record_sizes; + FT_Byte** hdmx_records; FT_Byte* sbit_table; FT_ULong sbit_table_size; @@ -1644,6 +1644,9 @@ void* cpal; void* colr; + /* since 2.12 */ + void* svg; + } TT_FaceRec; @@ -1734,7 +1737,7 @@ FT_UInt glyph_index; FT_Stream stream; - FT_Int byte_len; + FT_UInt byte_len; FT_Short n_contours; FT_BBox bbox; @@ -1769,6 +1772,9 @@ /* since version 2.6.2 */ FT_ListRec composites; + /* since version 2.11.2 */ + FT_Byte* widthp; + } TT_LoaderRec; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Basic WOFF/WOFF2 type definitions and interface (specification * only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -92,7 +92,7 @@ */ typedef struct WOFF_TableRec_ { - FT_ULong Tag; /* table ID */ + FT_Tag Tag; /* table ID */ FT_ULong Offset; /* table file offset */ FT_ULong CompLength; /* compressed table length */ FT_ULong OrigLength; /* uncompressed table length */ @@ -191,7 +191,7 @@ typedef struct WOFF2_TableRec_ { FT_Byte FlagByte; /* table type and flags */ - FT_ULong Tag; /* table file offset */ + FT_Tag Tag; /* table file offset */ FT_ULong dst_length; /* uncompressed table length */ FT_ULong TransformLength; /* transformed length */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,336 @@ +/**************************************************************************** + * + * otsvg.h + * + * Interface for OT-SVG support related things (specification). + * + * Copyright (C) 2022 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef OTSVG_H_ +#define OTSVG_H_ + +#include + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * svg_fonts + * + * @title: + * OpenType SVG Fonts + * + * @abstract: + * OT-SVG API between FreeType and an external SVG rendering library. + * + * @description: + * This section describes the four hooks necessary to render SVG + * 'documents' that are contained in an OpenType font's 'SVG~' table. + * + * For more information on the implementation, see our standard hooks + * based on 'librsvg' in the [FreeType Demo + * Programs](https://gitlab.freedesktop.org/freetype/freetype-demos) + * repository. + * + */ + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Init_Func + * + * @description: + * A callback that is called when the first OT-SVG glyph is rendered in + * the lifetime of an @FT_Library object. In a typical implementation, + * one would want to allocate a structure and point the `data_pointer` + * to it and perform any library initializations that might be needed. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Init_Func)( FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Free_Func + * + * @description: + * A callback that is called when the `ot-svg` module is being freed. + * It is only called if the init hook was called earlier. This means + * that neither the init nor the free hook is called if no OT-SVG glyph + * is rendered. + * + * In a typical implementation, one would want to free any state + * structure that was allocated in the init hook and perform any + * library-related closure that might be needed. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @since: + * 2.12 + */ + typedef void + (*SVG_Lib_Free_Func)( FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Render_Func + * + * @description: + * A callback that is called to render an OT-SVG glyph. This callback + * hook is called right after the preset hook @SVG_Lib_Preset_Slot_Func + * has been called with `cache` set to `TRUE`. The data necessary to + * render is available through the handle @FT_SVG_Document, which is set + * in the `other` field of @FT_GlyphSlotRec. + * + * The render hook is expected to render the SVG glyph to the bitmap + * buffer that is allocated already at `slot->bitmap.buffer`. It also + * sets the `num_grays` value as well as `slot->format`. + * + * @input: + * slot :: + * The slot to render. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Render_Func)( FT_GlyphSlot slot, + FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Preset_Slot_Func + * + * @description: + * A callback that is called to preset the glyph slot. It is called from + * two places. + * + * 1. When `FT_Load_Glyph` needs to preset the glyph slot. + * + * 2. Right before the `svg` module calls the render callback hook. + * + * When it is the former, the argument `cache` is set to `FALSE`. When + * it is the latter, the argument `cache` is set to `TRUE`. This + * distinction has been made because many calculations that are necessary + * for presetting a glyph slot are the same needed later for the render + * callback hook. Thus, if `cache` is `TRUE`, the hook can _cache_ those + * calculations in a memory block referenced by the state pointer. + * + * This hook is expected to preset the slot by setting parameters such as + * `bitmap_left`, `bitmap_top`, `width`, `rows`, `pitch`, and + * `pixel_mode`. It is also expected to set all the metrics for the slot + * including the vertical advance if it is not already set. Typically, + * fonts have horizontal advances but not vertical ones. If those are + * available, they had already been set, otherwise they have to be + * estimated and set manually. The hook must take into account the + * transformations that have been set, and translate the transformation + * matrices into the SVG coordinate system, as the original matrix is + * intended for the TTF/CFF coordinate system. + * + * @input: + * slot :: + * The glyph slot that has the SVG document loaded. + * + * cache :: + * See description. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Preset_Slot_Func)( FT_GlyphSlot slot, + FT_Bool cache, + FT_Pointer *state ); + + + /************************************************************************** + * + * @struct: + * SVG_RendererHooks + * + * @description: + * A structure that stores the four hooks needed to render OT-SVG glyphs + * properly. The structure is publicly used to set the hooks via the + * @svg-hooks driver property. + * + * The behavior of each hook is described in its documentation. One + * thing to note is that the preset hook and the render hook often need + * to do the same operations; therefore, it's better to cache the + * intermediate data in a state structure to avoid calculating it twice. + * For example, in the preset hook one can draw the glyph on a recorder + * surface and later create a bitmap surface from it in the render hook. + * + * All four hooks must be non-NULL. + * + * @fields: + * init_svg :: + * The initialization hook. + * + * free_svg :: + * The cleanup hook. + * + * render_hook :: + * The render hook. + * + * preset_slot :: + * The preset hook. + * + * @since: + * 2.12 + */ + typedef struct SVG_RendererHooks_ + { + SVG_Lib_Init_Func init_svg; + SVG_Lib_Free_Func free_svg; + SVG_Lib_Render_Func render_svg; + + SVG_Lib_Preset_Slot_Func preset_slot; + + } SVG_RendererHooks; + + + /************************************************************************** + * + * @struct: + * FT_SVG_DocumentRec + * + * @description: + * A structure that models one SVG document. + * + * @fields: + * svg_document :: + * A pointer to the SVG document. + * + * svg_document_length :: + * The length of `svg_document`. + * + * metrics :: + * A metrics object storing the size information. + * + * units_per_EM :: + * The size of the EM square. + * + * start_glyph_id :: + * The first glyph ID in the glyph range covered by this document. + * + * end_glyph_id :: + * The last glyph ID in the glyph range covered by this document. + * + * transform :: + * A 2x2 transformation matrix to apply to the glyph while rendering + * it. + * + * delta :: + * The translation to apply to the glyph while rendering. + * + * @note: + * When an @FT_GlyphSlot object `slot` is passed down to a renderer, the + * renderer can only access the `metrics` and `units_per_EM` fields via + * `slot->face`. However, when @FT_Glyph_To_Bitmap sets up a dummy + * object, it has no way to set a `face` object. Thus, metrics + * information and `units_per_EM` (which is necessary for OT-SVG) has to + * be stored separately. + * + * @since: + * 2.12 + */ + typedef struct FT_SVG_DocumentRec_ + { + FT_Byte* svg_document; + FT_ULong svg_document_length; + + FT_Size_Metrics metrics; + FT_UShort units_per_EM; + + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_Matrix transform; + FT_Vector delta; + + } FT_SVG_DocumentRec; + + + /************************************************************************** + * + * @type: + * FT_SVG_Document + * + * @description: + * A handle to an @FT_SVG_DocumentRec object. + * + * @since: + * 2.12 + */ + typedef struct FT_SVG_DocumentRec_* FT_SVG_Document; + + +FT_END_HEADER + +#endif /* OTSVG_H_ */ + + +/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Basic Type 1/Type 2 tables definitions and interface (specification * only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -360,7 +360,7 @@ FT_UInt num_subrs; FT_ULong subrmap_offset; - FT_Int sd_bytes; + FT_UInt sd_bytes; } CID_FaceDictRec; @@ -415,11 +415,11 @@ FT_ULong xuid[16]; FT_ULong cidmap_offset; - FT_Int fd_bytes; - FT_Int gd_bytes; + FT_UInt fd_bytes; + FT_UInt gd_bytes; FT_ULong cid_count; - FT_Int num_dicts; + FT_UInt num_dicts; CID_FaceDict font_dicts; FT_ULong data_offset; @@ -453,22 +453,22 @@ /************************************************************************** * * @function: - * FT_Has_PS_Glyph_Names + * FT_Has_PS_Glyph_Names * * @description: - * Return true if a given face provides reliable PostScript glyph names. - * This is similar to using the @FT_HAS_GLYPH_NAMES macro, except that - * certain fonts (mostly TrueType) contain incorrect glyph name tables. + * Return true if a given face provides reliable PostScript glyph names. + * This is similar to using the @FT_HAS_GLYPH_NAMES macro, except that + * certain fonts (mostly TrueType) contain incorrect glyph name tables. * - * When this function returns true, the caller is sure that the glyph - * names returned by @FT_Get_Glyph_Name are reliable. + * When this function returns true, the caller is sure that the glyph + * names returned by @FT_Get_Glyph_Name are reliable. * * @input: - * face :: - * face handle + * face :: + * face handle * * @return: - * Boolean. True if glyph names are reliable. + * Boolean. True if glyph names are reliable. * */ FT_EXPORT( FT_Int ) @@ -478,30 +478,40 @@ /************************************************************************** * * @function: - * FT_Get_PS_Font_Info + * FT_Get_PS_Font_Info * * @description: - * Retrieve the @PS_FontInfoRec structure corresponding to a given - * PostScript font. + * Retrieve the @PS_FontInfoRec structure corresponding to a given + * PostScript font. * * @input: - * face :: - * PostScript face handle. + * face :: + * PostScript face handle. * * @output: - * afont_info :: - * Output font info structure pointer. + * afont_info :: + * A pointer to a @PS_FontInfoRec object. * * @return: - * FreeType error code. 0~means success. + * FreeType error code. 0~means success. * * @note: - * String pointers within the @PS_FontInfoRec structure are owned by the - * face and don't need to be freed by the caller. Missing entries in - * the font's FontInfo dictionary are represented by `NULL` pointers. - * - * If the font's format is not PostScript-based, this function will - * return the `FT_Err_Invalid_Argument` error code. + * String pointers within the @PS_FontInfoRec structure are owned by the + * face and don't need to be freed by the caller. Missing entries in the + * font's FontInfo dictionary are represented by `NULL` pointers. + * + * The following font formats support this feature: 'Type~1', 'Type~42', + * 'CFF', 'CID~Type~1'. For other font formats this function returns the + * `FT_Err_Invalid_Argument` error code. + * + * @example: + * ``` + * PS_FontInfoRec font_info; + * + * + * error = FT_Get_PS_Font_Info( face, &font_info ); + * ... + * ``` * */ FT_EXPORT( FT_Error ) @@ -512,29 +522,39 @@ /************************************************************************** * * @function: - * FT_Get_PS_Font_Private + * FT_Get_PS_Font_Private * * @description: - * Retrieve the @PS_PrivateRec structure corresponding to a given - * PostScript font. + * Retrieve the @PS_PrivateRec structure corresponding to a given + * PostScript font. * * @input: - * face :: - * PostScript face handle. + * face :: + * PostScript face handle. * * @output: - * afont_private :: - * Output private dictionary structure pointer. + * afont_private :: + * A pointer to a @PS_PrivateRec object. * * @return: - * FreeType error code. 0~means success. + * FreeType error code. 0~means success. * * @note: - * The string pointers within the @PS_PrivateRec structure are owned by - * the face and don't need to be freed by the caller. + * The string pointers within the @PS_PrivateRec structure are owned by + * the face and don't need to be freed by the caller. + * + * Only the 'Type~1' font format supports this feature. For other font + * formats this function returns the `FT_Err_Invalid_Argument` error + * code. * - * If the font's format is not PostScript-based, this function returns - * the `FT_Err_Invalid_Argument` error code. + * @example: + * ``` + * PS_PrivateRec font_private; + * + * + * error = FT_Get_PS_Font_Private( face, &font_private ); + * ... + * ``` * */ FT_EXPORT( FT_Error ) @@ -693,67 +713,67 @@ /************************************************************************** * * @function: - * FT_Get_PS_Font_Value + * FT_Get_PS_Font_Value * * @description: - * Retrieve the value for the supplied key from a PostScript font. + * Retrieve the value for the supplied key from a PostScript font. * * @input: - * face :: - * PostScript face handle. + * face :: + * PostScript face handle. * - * key :: - * An enumeration value representing the dictionary key to retrieve. + * key :: + * An enumeration value representing the dictionary key to retrieve. * - * idx :: - * For array values, this specifies the index to be returned. + * idx :: + * For array values, this specifies the index to be returned. * - * value :: - * A pointer to memory into which to write the value. + * value :: + * A pointer to memory into which to write the value. * - * valen_len :: - * The size, in bytes, of the memory supplied for the value. + * valen_len :: + * The size, in bytes, of the memory supplied for the value. * * @output: - * value :: - * The value matching the above key, if it exists. + * value :: + * The value matching the above key, if it exists. * * @return: - * The amount of memory (in bytes) required to hold the requested value - * (if it exists, -1 otherwise). + * The amount of memory (in bytes) required to hold the requested value + * (if it exists, -1 otherwise). * * @note: - * The values returned are not pointers into the internal structures of - * the face, but are 'fresh' copies, so that the memory containing them - * belongs to the calling application. This also enforces the - * 'read-only' nature of these values, i.e., this function cannot be - * used to manipulate the face. - * - * `value` is a void pointer because the values returned can be of - * various types. - * - * If either `value` is `NULL` or `value_len` is too small, just the - * required memory size for the requested entry is returned. - * - * The `idx` parameter is used, not only to retrieve elements of, for - * example, the FontMatrix or FontBBox, but also to retrieve name keys - * from the CharStrings dictionary, and the charstrings themselves. It - * is ignored for atomic values. - * - * `PS_DICT_BLUE_SCALE` returns a value that is scaled up by 1000. To - * get the value as in the font stream, you need to divide by 65536000.0 - * (to remove the FT_Fixed scale, and the x1000 scale). - * - * IMPORTANT: Only key/value pairs read by the FreeType interpreter can - * be retrieved. So, for example, PostScript procedures such as NP, ND, - * and RD are not available. Arbitrary keys are, obviously, not be - * available either. + * The values returned are not pointers into the internal structures of + * the face, but are 'fresh' copies, so that the memory containing them + * belongs to the calling application. This also enforces the + * 'read-only' nature of these values, i.e., this function cannot be + * used to manipulate the face. + * + * `value` is a void pointer because the values returned can be of + * various types. + * + * If either `value` is `NULL` or `value_len` is too small, just the + * required memory size for the requested entry is returned. + * + * The `idx` parameter is used, not only to retrieve elements of, for + * example, the FontMatrix or FontBBox, but also to retrieve name keys + * from the CharStrings dictionary, and the charstrings themselves. It + * is ignored for atomic values. + * + * `PS_DICT_BLUE_SCALE` returns a value that is scaled up by 1000. To + * get the value as in the font stream, you need to divide by 65536000.0 + * (to remove the FT_Fixed scale, and the x1000 scale). + * + * IMPORTANT: Only key/value pairs read by the FreeType interpreter can + * be retrieved. So, for example, PostScript procedures such as NP, ND, + * and RD are not available. Arbitrary keys are, obviously, not be + * available either. * - * If the font's format is not PostScript-based, this function returns - * the `FT_Err_Invalid_Argument` error code. + * If the font's format is not PostScript-based, this function returns + * the `FT_Err_Invalid_Argument` error code. * * @since: - * 2.4.8 + * 2.4.8 * */ FT_EXPORT( FT_Long ) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType name ID definitions (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -591,7 +591,7 @@ #define TT_MS_LANGID_MALAY_MALAYSIA 0x043E #define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083E #define TT_MS_LANGID_KAZAKH_KAZAKHSTAN 0x043F -#define TT_MS_LANGID_KYRGYZ_KYRGYZSTAN /* Cyrillic*/ 0x0440 +#define TT_MS_LANGID_KYRGYZ_KYRGYZSTAN /* Cyrillic */ 0x0440 #define TT_MS_LANGID_KISWAHILI_KENYA 0x0441 #define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442 #define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Basic SFNT/TrueType tables definitions and interface * (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Tags for TrueType and OpenType tables (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -95,6 +95,7 @@ #define TTAG_sbix FT_MAKE_TAG( 's', 'b', 'i', 'x' ) #define TTAG_sfnt FT_MAKE_TAG( 's', 'f', 'n', 't' ) #define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) +#define TTAG_SVG FT_MAKE_TAG( 'S', 'V', 'G', ' ' ) #define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' ) #define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) #define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/ft2build.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/ft2build.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/include/ft2build.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/include/ft2build.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType 2 build and setup macros. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afangles.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afangles.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afangles.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afangles.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,285 +0,0 @@ -/**************************************************************************** - * - * afangles.c - * - * Routines used to compute vector angles with limited accuracy - * and very high speed. It also contains sorting routines (body). - * - * Copyright (C) 2003-2020 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.TXT. By continuing to use, modify, or distribute - * this file you indicate that you have read the license and - * understand and accept it fully. - * - */ - - -#include "aftypes.h" - - - /* - * We are not using `af_angle_atan' anymore, but we keep the source - * code below just in case... - */ - - -#if 0 - - - /* - * The trick here is to realize that we don't need a very accurate angle - * approximation. We are going to use the result of `af_angle_atan' to - * only compare the sign of angle differences, or check whether its - * magnitude is very small. - * - * The approximation - * - * dy * PI / (|dx|+|dy|) - * - * should be enough, and much faster to compute. - */ - FT_LOCAL_DEF( AF_Angle ) - af_angle_atan( FT_Fixed dx, - FT_Fixed dy ) - { - AF_Angle angle; - FT_Fixed ax = dx; - FT_Fixed ay = dy; - - - if ( ax < 0 ) - ax = -ax; - if ( ay < 0 ) - ay = -ay; - - ax += ay; - - if ( ax == 0 ) - angle = 0; - else - { - angle = ( AF_ANGLE_PI2 * dy ) / ( ax + ay ); - if ( dx < 0 ) - { - if ( angle >= 0 ) - angle = AF_ANGLE_PI - angle; - else - angle = -AF_ANGLE_PI - angle; - } - } - - return angle; - } - - -#elif 0 - - - /* the following table has been automatically generated with */ - /* the `mather.py' Python script */ - -#define AF_ATAN_BITS 8 - - static const FT_Byte af_arctan[1L << AF_ATAN_BITS] = - { - 0, 0, 1, 1, 1, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 5, - 5, 5, 6, 6, 6, 7, 7, 7, - 8, 8, 8, 9, 9, 9, 10, 10, - 10, 10, 11, 11, 11, 12, 12, 12, - 13, 13, 13, 14, 14, 14, 14, 15, - 15, 15, 16, 16, 16, 17, 17, 17, - 18, 18, 18, 18, 19, 19, 19, 20, - 20, 20, 21, 21, 21, 21, 22, 22, - 22, 23, 23, 23, 24, 24, 24, 24, - 25, 25, 25, 26, 26, 26, 26, 27, - 27, 27, 28, 28, 28, 28, 29, 29, - 29, 30, 30, 30, 30, 31, 31, 31, - 31, 32, 32, 32, 33, 33, 33, 33, - 34, 34, 34, 34, 35, 35, 35, 35, - 36, 36, 36, 36, 37, 37, 37, 38, - 38, 38, 38, 39, 39, 39, 39, 40, - 40, 40, 40, 41, 41, 41, 41, 42, - 42, 42, 42, 42, 43, 43, 43, 43, - 44, 44, 44, 44, 45, 45, 45, 45, - 46, 46, 46, 46, 46, 47, 47, 47, - 47, 48, 48, 48, 48, 48, 49, 49, - 49, 49, 50, 50, 50, 50, 50, 51, - 51, 51, 51, 51, 52, 52, 52, 52, - 52, 53, 53, 53, 53, 53, 54, 54, - 54, 54, 54, 55, 55, 55, 55, 55, - 56, 56, 56, 56, 56, 57, 57, 57, - 57, 57, 57, 58, 58, 58, 58, 58, - 59, 59, 59, 59, 59, 59, 60, 60, - 60, 60, 60, 61, 61, 61, 61, 61, - 61, 62, 62, 62, 62, 62, 62, 63, - 63, 63, 63, 63, 63, 64, 64, 64 - }; - - - FT_LOCAL_DEF( AF_Angle ) - af_angle_atan( FT_Fixed dx, - FT_Fixed dy ) - { - AF_Angle angle; - - - /* check trivial cases */ - if ( dy == 0 ) - { - angle = 0; - if ( dx < 0 ) - angle = AF_ANGLE_PI; - return angle; - } - else if ( dx == 0 ) - { - angle = AF_ANGLE_PI2; - if ( dy < 0 ) - angle = -AF_ANGLE_PI2; - return angle; - } - - angle = 0; - if ( dx < 0 ) - { - dx = -dx; - dy = -dy; - angle = AF_ANGLE_PI; - } - - if ( dy < 0 ) - { - FT_Pos tmp; - - - tmp = dx; - dx = -dy; - dy = tmp; - angle -= AF_ANGLE_PI2; - } - - if ( dx == 0 && dy == 0 ) - return 0; - - if ( dx == dy ) - angle += AF_ANGLE_PI4; - else if ( dx > dy ) - angle += af_arctan[FT_DivFix( dy, dx ) >> ( 16 - AF_ATAN_BITS )]; - else - angle += AF_ANGLE_PI2 - - af_arctan[FT_DivFix( dx, dy ) >> ( 16 - AF_ATAN_BITS )]; - - if ( angle > AF_ANGLE_PI ) - angle -= AF_ANGLE_2PI; - - return angle; - } - - -#endif /* 0 */ - - - FT_LOCAL_DEF( void ) - af_sort_pos( FT_UInt count, - FT_Pos* table ) - { - FT_UInt i, j; - FT_Pos swap; - - - for ( i = 1; i < count; i++ ) - { - for ( j = i; j > 0; j-- ) - { - if ( table[j] >= table[j - 1] ) - break; - - swap = table[j]; - table[j] = table[j - 1]; - table[j - 1] = swap; - } - } - } - - - FT_LOCAL_DEF( void ) - af_sort_and_quantize_widths( FT_UInt* count, - AF_Width table, - FT_Pos threshold ) - { - FT_UInt i, j; - FT_UInt cur_idx; - FT_Pos cur_val; - FT_Pos sum; - AF_WidthRec swap; - - - if ( *count == 1 ) - return; - - /* sort */ - for ( i = 1; i < *count; i++ ) - { - for ( j = i; j > 0; j-- ) - { - if ( table[j].org >= table[j - 1].org ) - break; - - swap = table[j]; - table[j] = table[j - 1]; - table[j - 1] = swap; - } - } - - cur_idx = 0; - cur_val = table[cur_idx].org; - - /* compute and use mean values for clusters not larger than */ - /* `threshold'; this is very primitive and might not yield */ - /* the best result, but normally, using reference character */ - /* `o', `*count' is 2, so the code below is fully sufficient */ - for ( i = 1; i < *count; i++ ) - { - if ( table[i].org - cur_val > threshold || - i == *count - 1 ) - { - sum = 0; - - /* fix loop for end of array */ - if ( table[i].org - cur_val <= threshold && - i == *count - 1 ) - i++; - - for ( j = cur_idx; j < i; j++ ) - { - sum += table[j].org; - table[j].org = 0; - } - table[cur_idx].org = sum / (FT_Pos)j; - - if ( i < *count - 1 ) - { - cur_idx = i + 1; - cur_val = table[cur_idx].org; - } - } - } - - cur_idx = 1; - - /* compress array to remove zero values */ - for ( i = 1; i < *count; i++ ) - { - if ( table[i].org ) - table[cur_idx++] = table[i]; - } - - *count = cur_idx; - } - - -/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afangles.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afangles.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afangles.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afangles.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -/* - * afangles.h - * - * This is a dummy file, used to please the build system. It is never - * included by the auto-fitter sources. - * - */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c 2022-07-14 08:05:38.000000000 +0000 @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat 2022-07-14 08:05:38.000000000 +0000 @@ -2,7 +2,7 @@ // // Auto-fitter data for blue strings. // -// Copyright (C) 2013-2020 by +// Copyright (C) 2013-2022 by // David Turner, Robert Wilhelm, and Werner Lemberg. // // This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h 2022-07-14 08:05:38.000000000 +0000 @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (body). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -37,11 +37,6 @@ #include "aferrors.h" -#ifdef AF_CONFIG_OPTION_USE_WARPER -#include "afwarp.h" -#endif - - /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit @@ -72,11 +67,11 @@ AF_GlyphHintsRec hints[1]; - FT_TRACE5(( "\n" - "cjk standard widths computation (style `%s')\n" - "===================================================\n" - "\n", + FT_TRACE5(( "\n" )); + FT_TRACE5(( "cjk standard widths computation (style `%s')\n", af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "===================================================\n" )); + FT_TRACE5(( "\n" )); af_glyph_hints_init( hints, face->memory ); @@ -314,9 +309,9 @@ /* style's entry in the `af_blue_stringset' array, computing its */ /* extremum points (depending on the string properties) */ - FT_TRACE5(( "cjk blue zones computation\n" - "==========================\n" - "\n" )); + FT_TRACE5(( "cjk blue zones computation\n" )); + FT_TRACE5(( "==========================\n" )); + FT_TRACE5(( "\n" )); #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ shaper_buf = af_shaper_buf_create( face ); @@ -555,9 +550,8 @@ if ( AF_CJK_IS_TOP_BLUE( bs ) ) blue->flags |= AF_CJK_BLUE_TOP; - FT_TRACE5(( " -> reference = %ld\n" - " overshoot = %ld\n", - *blue_ref, *blue_shoot )); + FT_TRACE5(( " -> reference = %ld\n", *blue_ref )); + FT_TRACE5(( " overshoot = %ld\n", *blue_shoot )); } /* end for loop */ @@ -743,12 +737,12 @@ blue->shoot.fit = blue->ref.fit - delta2; - FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n" - " ref: cur=%.2f fit=%.2f\n" - " shoot: cur=%.2f fit=%.2f\n", + FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n", ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', - nn, blue->ref.org, blue->shoot.org, - blue->ref.cur / 64.0, blue->ref.fit / 64.0, + nn, blue->ref.org, blue->shoot.org )); + FT_TRACE5(( " ref: cur=%.2f fit=%.2f\n", + blue->ref.cur / 64.0, blue->ref.fit / 64.0 )); + FT_TRACE5(( " shoot: cur=%.2f fit=%.2f\n", blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 )); blue->flags |= AF_CJK_BLUE_ACTIVE; @@ -849,7 +843,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Direction major_dir = axis->major_dir; AF_Segment seg1, seg2; FT_Pos len_threshold; @@ -1011,7 +1005,7 @@ AF_CJKAxis laxis = &((AF_CJKMetrics)hints->metrics)->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Segment seg; FT_Fixed scale; @@ -1159,7 +1153,7 @@ */ { AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); AF_Edge edge; @@ -1297,7 +1291,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edge = axis->edges; - AF_Edge edge_limit = edge + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges ); AF_CJKAxis cjk = &metrics->axis[dim]; FT_Fixed scale = cjk->scale; FT_Pos best_dist0; /* initial threshold */ @@ -1401,11 +1395,6 @@ /* compute flags depending on render mode, etc. */ mode = metrics->root.scaler.render_mode; -#if 0 /* AF_CONFIG_OPTION_USE_WARPER */ - if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V ) - metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL; -#endif - scaler_flags = hints->scaler_flags; other_flags = 0; @@ -1434,12 +1423,6 @@ scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE; -#ifdef AF_CONFIG_OPTION_USE_WARPER - /* get (global) warper flag */ - if ( !metrics->root.globals->module->warping ) - scaler_flags |= AF_SCALER_FLAG_NO_WARPER; -#endif - hints->scaler_flags = scaler_flags; hints->other_flags = other_flags; @@ -1815,7 +1798,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); FT_PtrDist n_edges; AF_Edge edge; AF_Edge anchor = NULL; @@ -2194,7 +2177,7 @@ { AF_AxisHints axis = & hints->axis[dim]; AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); AF_Edge edge; FT_Bool snapping; @@ -2322,25 +2305,6 @@ if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { - -#ifdef AF_CONFIG_OPTION_USE_WARPER - if ( dim == AF_DIMENSION_HORZ && - metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL && - AF_HINTS_DO_WARP( hints ) ) - { - AF_WarperRec warper; - FT_Fixed scale; - FT_Pos delta; - - - af_warper_compute( &warper, hints, (AF_Dimension)dim, - &scale, &delta ); - af_glyph_hints_scale_dim( hints, (AF_Dimension)dim, - scale, delta ); - continue; - } -#endif /* AF_CONFIG_OPTION_USE_WARPER */ - af_cjk_hint_edges( hints, (AF_Dimension)dim ); af_cjk_align_edge_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (specification). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter coverages (specification only). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (body). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Autofitter error codes (specification only). * - * Copyright (C) 2005-2020 by + * Copyright (C) 2005-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter routines to compute global hinting values (body). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,6 +19,7 @@ #include "afglobal.h" #include "afranges.h" #include "afshaper.h" +#include "afws-decl.h" #include @@ -32,11 +33,6 @@ #define FT_COMPONENT afglobal - /* get writing system specific header files */ -#undef WRITING_SYSTEM -#define WRITING_SYSTEM( ws, WS ) /* empty */ -#include "afwrtsys.h" - #include "aferrors.h" @@ -74,7 +70,7 @@ af_writing_system_classes[] = { -#include "afwrtsys.h" +#include "afws-iter.h" NULL /* do not remove */ }; @@ -285,10 +281,10 @@ #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE4(( "\n" - "style coverage\n" - "==============\n" - "\n" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "style coverage\n" )); + FT_TRACE4(( "==============\n" )); + FT_TRACE4(( "\n" )); for ( ss = 0; af_style_classes[ss]; ss++ ) { @@ -341,11 +337,13 @@ /* we allocate an AF_FaceGlobals structure together */ /* with the glyph_styles array */ - if ( FT_ALLOC( globals, - sizeof ( *globals ) + - (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) ) + if ( FT_QALLOC( globals, + sizeof ( *globals ) + + (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) ) goto Exit; + FT_ZERO( &globals->metrics ); + globals->face = face; globals->glyph_count = face->num_glyphs; /* right after the globals structure come the glyph styles */ @@ -478,6 +476,10 @@ { style = (AF_Style)( globals->glyph_styles[gindex] & AF_STYLE_UNASSIGNED ); + /* IMPORTANT: Clear the error code, see + * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1063 + */ + error = FT_Err_Ok; goto Again; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Auto-fitter routines to compute global hinting values * (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (body). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -32,6 +32,104 @@ #define FT_COMPONENT afhints + FT_LOCAL_DEF( void ) + af_sort_pos( FT_UInt count, + FT_Pos* table ) + { + FT_UInt i, j; + FT_Pos swap; + + + for ( i = 1; i < count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + if ( table[j] >= table[j - 1] ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + } + + + FT_LOCAL_DEF( void ) + af_sort_and_quantize_widths( FT_UInt* count, + AF_Width table, + FT_Pos threshold ) + { + FT_UInt i, j; + FT_UInt cur_idx; + FT_Pos cur_val; + FT_Pos sum; + AF_WidthRec swap; + + + if ( *count == 1 ) + return; + + /* sort */ + for ( i = 1; i < *count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + if ( table[j].org >= table[j - 1].org ) + break; + + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + + cur_idx = 0; + cur_val = table[cur_idx].org; + + /* compute and use mean values for clusters not larger than */ + /* `threshold'; this is very primitive and might not yield */ + /* the best result, but normally, using reference character */ + /* `o', `*count' is 2, so the code below is fully sufficient */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org - cur_val > threshold || + i == *count - 1 ) + { + sum = 0; + + /* fix loop for end of array */ + if ( table[i].org - cur_val <= threshold && + i == *count - 1 ) + i++; + + for ( j = cur_idx; j < i; j++ ) + { + sum += table[j].org; + table[j].org = 0; + } + table[cur_idx].org = sum / (FT_Pos)j; + + if ( i < *count - 1 ) + { + cur_idx = i + 1; + cur_val = table[cur_idx].org; + } + } + } + + cur_idx = 1; + + /* compress array to remove zero values */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org ) + table[cur_idx++] = table[i]; + } + + *count = cur_idx; + } + /* Get new segment for given axis. */ FT_LOCAL_DEF( FT_Error ) @@ -764,7 +862,7 @@ { FT_Error error = FT_Err_Ok; AF_Point points; - FT_UInt old_max, new_max; + FT_Int old_max, new_max; FT_Fixed x_scale = hints->x_scale; FT_Fixed y_scale = hints->y_scale; FT_Pos x_delta = hints->x_delta; @@ -781,8 +879,8 @@ hints->axis[1].num_edges = 0; /* first of all, reallocate the contours array if necessary */ - new_max = (FT_UInt)outline->n_contours; - old_max = (FT_UInt)hints->max_contours; + new_max = outline->n_contours; + old_max = hints->max_contours; if ( new_max <= AF_CONTOURS_EMBEDDED ) { @@ -797,12 +895,12 @@ if ( hints->contours == hints->embedded.contours ) hints->contours = NULL; - new_max = ( new_max + 3 ) & ~3U; /* round up to a multiple of 4 */ + new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */ if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) goto Exit; - hints->max_contours = (FT_Int)new_max; + hints->max_contours = new_max; } /* @@ -810,8 +908,8 @@ * note that we reserve two additional point positions, used to * hint metrics appropriately */ - new_max = (FT_UInt)( outline->n_points + 2 ); - old_max = (FT_UInt)hints->max_points; + new_max = outline->n_points + 2; + old_max = hints->max_points; if ( new_max <= AF_POINTS_EMBEDDED ) { @@ -826,12 +924,12 @@ if ( hints->points == hints->embedded.points ) hints->points = NULL; - new_max = ( new_max + 2 + 7 ) & ~7U; /* round up to a multiple of 8 */ + new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */ if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) goto Exit; - hints->max_points = (FT_Int)new_max; + hints->max_points = new_max; } hints->num_points = outline->n_points; @@ -855,9 +953,6 @@ hints->x_delta = x_delta; hints->y_delta = y_delta; - hints->xmin_delta = 0; - hints->xmax_delta = 0; - points = hints->points; if ( hints->num_points == 0 ) goto Exit; @@ -1221,7 +1316,7 @@ { AF_AxisHints axis = & hints->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Segment seg; @@ -1298,7 +1393,7 @@ AF_Point point_limit = points + hints->num_points; AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); FT_UInt touch_flag; @@ -1688,33 +1783,4 @@ } -#ifdef AF_CONFIG_OPTION_USE_WARPER - - /* Apply (small) warp scale and warp delta for given dimension. */ - - FT_LOCAL_DEF( void ) - af_glyph_hints_scale_dim( AF_GlyphHints hints, - AF_Dimension dim, - FT_Fixed scale, - FT_Pos delta ) - { - AF_Point points = hints->points; - AF_Point points_limit = points + hints->num_points; - AF_Point point; - - - if ( dim == AF_DIMENSION_HORZ ) - { - for ( point = points; point < points_limit; point++ ) - point->x = FT_MulFix( point->fx, scale ) + delta; - } - else - { - for ( point = points; point < points_limit; point++ ) - point->y = FT_MulFix( point->fy, scale ) + delta; - } - } - -#endif /* AF_CONFIG_OPTION_USE_WARPER */ - /* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -362,9 +362,6 @@ /* implementations */ AF_StyleMetrics metrics; - FT_Pos xmin_delta; /* used for warping */ - FT_Pos xmax_delta; - /* Two arrays to avoid allocation penalty. */ /* The `embedded' structure must be the last element! */ struct @@ -408,10 +405,6 @@ #define AF_HINTS_DO_ADVANCE( h ) \ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE ) -#define AF_HINTS_DO_WARP( h ) \ - !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_WARPER ) - - FT_LOCAL( AF_Direction ) af_direction_compute( FT_Pos dx, @@ -459,14 +452,6 @@ af_glyph_hints_align_weak_points( AF_GlyphHints hints, AF_Dimension dim ); -#ifdef AF_CONFIG_OPTION_USE_WARPER - FT_LOCAL( void ) - af_glyph_hints_scale_dim( AF_GlyphHints hints, - AF_Dimension dim, - FT_Fixed scale, - FT_Pos delta ); -#endif - FT_LOCAL( void ) af_glyph_hints_done( AF_GlyphHints hints ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for Indic writing system (body). * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, @@ -27,11 +27,6 @@ #include "aferrors.h" -#ifdef AF_CONFIG_OPTION_USE_WARPER -#include "afwarp.h" -#endif - - static FT_Error af_indic_metrics_init( AF_CJKMetrics metrics, FT_Face face ) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for Indic writing system * (specification). * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for latin writing system (body). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -24,11 +24,6 @@ #include "aferrors.h" -#ifdef AF_CONFIG_OPTION_USE_WARPER -#include "afwarp.h" -#endif - - /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit @@ -63,11 +58,11 @@ AF_GlyphHintsRec hints[1]; - FT_TRACE5(( "\n" - "latin standard widths computation (style `%s')\n" - "=====================================================\n" - "\n", + FT_TRACE5(( "\n" )); + FT_TRACE5(( "latin standard widths computation (style `%s')\n", af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "=====================================================\n" )); + FT_TRACE5(( "\n" )); af_glyph_hints_init( hints, face->memory ); @@ -205,7 +200,7 @@ (AF_Dimension)dim ); seg = axhints->segments; - limit = seg + axhints->num_segments; + limit = FT_OFFSET( seg, axhints->num_segments ); for ( ; seg < limit; seg++ ) { @@ -350,9 +345,9 @@ /* we walk over the blue character strings as specified in the */ /* style's entry in the `af_blue_stringset' array */ - FT_TRACE5(( "latin blue zones computation\n" - "============================\n" - "\n" )); + FT_TRACE5(( "latin blue zones computation\n" )); + FT_TRACE5(( "============================\n" )); + FT_TRACE5(( "\n" )); #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ shaper_buf = af_shaper_buf_create( face ); @@ -976,9 +971,8 @@ if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; - FT_TRACE5(( " -> reference = %ld\n" - " overshoot = %ld\n", - *blue_ref, *blue_shoot )); + FT_TRACE5(( " -> reference = %ld\n", *blue_ref )); + FT_TRACE5(( " overshoot = %ld\n", *blue_shoot )); } /* end for loop */ @@ -1275,29 +1269,28 @@ if ( dist == 0 ) { - FT_TRACE5(( - "af_latin_metrics_scale_dim:" - " x height alignment (style `%s'):\n" - " " - " vertical scaling changed from %.5f to %.5f (by %ld%%)\n" - "\n", - af_style_names[metrics->root.style_class->style], - scale / 65536.0, - new_scale / 65536.0, - ( fitted - scaled ) * 100 / scaled )); + FT_TRACE5(( "af_latin_metrics_scale_dim:" + " x height alignment (style `%s'):\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( " " + " vertical scaling changed" + " from %.5f to %.5f (by %ld%%)\n", + scale / 65536.0, + new_scale / 65536.0, + ( fitted - scaled ) * 100 / scaled )); + FT_TRACE5(( "\n" )); scale = new_scale; } #ifdef FT_DEBUG_LEVEL_TRACE else { - FT_TRACE5(( - "af_latin_metrics_scale_dim:" - " x height alignment (style `%s'):\n" - " " - " excessive vertical scaling abandoned\n" - "\n", - af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "af_latin_metrics_scale_dim:" + " x height alignment (style `%s'):\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( " " + " excessive vertical scaling abandoned\n" )); + FT_TRACE5(( "\n" )); } #endif } @@ -1346,9 +1339,11 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( axis->extra_light ) - FT_TRACE5(( "`%s' style is extra light (at current resolution)\n" - "\n", + { + FT_TRACE5(( "`%s' style is extra light (at current resolution)\n", af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "\n" )); + } #endif if ( dim == AF_DIMENSION_VERT ) @@ -1473,13 +1468,13 @@ AF_LatinBlue blue = &axis->blues[nn]; - FT_TRACE5(( " reference %d: %ld scaled to %.2f%s\n" - " overshoot %d: %ld scaled to %.2f%s\n", + FT_TRACE5(( " reference %d: %ld scaled to %.2f%s\n", nn, blue->ref.org, blue->ref.fit / 64.0, ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? "" - : " (inactive)", + : " (inactive)" )); + FT_TRACE5(( " overshoot %d: %ld scaled to %.2f%s\n", nn, blue->shoot.org, blue->shoot.fit / 64.0, @@ -1847,6 +1842,31 @@ ( FT_ABS( point->out_dir ) == major_dir || point == point->prev ) ) { + /* + * For efficiency, we restrict the number of segments to 1000, + * which is a heuristic value: it is very unlikely that a glyph + * with so many segments can be hinted in a sensible way. + * Reasons: + * + * - The glyph has really 1000 segments; this implies that it has + * at least 2000 outline points. Assuming 'normal' fonts that + * have superfluous points optimized away, viewing such a glyph + * only makes sense at large magnifications where hinting + * isn't applied anyway. + * + * - We have a broken glyph. Hinting doesn't make sense in this + * case either. + */ + if ( axis->num_segments > 1000 ) + { + FT_TRACE0(( "af_latin_hints_compute_segments:" + " more than 1000 segments in this glyph;\n" )); + FT_TRACE0(( " " + " hinting is suppressed\n" )); + axis->num_segments = 0; + return FT_Err_Ok; + } + /* this is the start of a new segment! */ segment_dir = (AF_Direction)point->out_dir; @@ -1969,7 +1989,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); FT_Pos len_threshold, len_score, dist_score, max_width; AF_Segment seg1, seg2; @@ -2089,7 +2109,7 @@ { if ( seg2->link != seg1 ) { - seg1->link = 0; + seg1->link = NULL; seg1->serif = seg2->link; } } @@ -2114,7 +2134,7 @@ FT_Bool top_to_bottom_hinting = 0; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Segment seg; #if 0 @@ -2480,7 +2500,7 @@ { AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; AF_Edge edge = axis->edges; - AF_Edge edge_limit = edge + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges ); AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT]; FT_Fixed scale = latin->scale; @@ -2611,11 +2631,6 @@ /* compute flags depending on render mode, etc. */ mode = metrics->root.scaler.render_mode; -#if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */ - if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V ) - metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL; -#endif - scaler_flags = hints->scaler_flags; other_flags = 0; @@ -2653,12 +2668,6 @@ ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; -#ifdef AF_CONFIG_OPTION_USE_WARPER - /* get (global) warper flag */ - if ( !metrics->root.globals->module->warping ) - scaler_flags |= AF_SCALER_FLAG_NO_WARPER; -#endif - hints->scaler_flags = scaler_flags; hints->other_flags = other_flags; @@ -2984,7 +2993,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); FT_PtrDist n_edges; AF_Edge edge; AF_Edge anchor = NULL; @@ -3575,24 +3584,6 @@ /* grid-fit the outline */ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { -#ifdef AF_CONFIG_OPTION_USE_WARPER - if ( dim == AF_DIMENSION_HORZ && - metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL && - AF_HINTS_DO_WARP( hints ) ) - { - AF_WarperRec warper; - FT_Fixed scale; - FT_Pos delta; - - - af_warper_compute( &warper, hints, (AF_Dimension)dim, - &scale, &delta ); - af_glyph_hints_scale_dim( hints, (AF_Dimension)dim, - scale, delta ); - continue; - } -#endif /* AF_CONFIG_OPTION_USE_WARPER */ - if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for latin writing system * (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (body). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -105,7 +105,6 @@ globals->stem_darkening_for_ppem; FT_Fixed em_size = af_intToFixed( face->units_per_EM ); - FT_Fixed em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size ); FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L }; @@ -142,12 +141,11 @@ darken_by_font_units_x = - af_intToFixed( af_loader_compute_darkening( loader, - face, - stdVW ) ); - darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x, - size_metrics->x_scale ), - em_ratio ); + af_loader_compute_darkening( loader, + face, + stdVW ) ; + darken_x = FT_MulFix( darken_by_font_units_x, + size_metrics->x_scale ); globals->standard_vertical_width = stdVW; globals->stem_darkening_for_ppem = size_metrics->x_ppem; @@ -161,12 +159,11 @@ darken_by_font_units_y = - af_intToFixed( af_loader_compute_darkening( loader, - face, - stdHW ) ); - darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y, - size_metrics->y_scale ), - em_ratio ); + af_loader_compute_darkening( loader, + face, + stdHW ) ; + darken_y = FT_MulFix( darken_by_font_units_y, + size_metrics->y_scale ); globals->standard_horizontal_width = stdHW; globals->stem_darkening_for_ppem = size_metrics->x_ppem; @@ -300,12 +297,6 @@ if ( error ) goto Exit; -#ifdef FT_OPTION_AUTOFIT2 - /* XXX: undocumented hook to activate the latin2 writing system. */ - if ( load_flags & ( 1UL << 20 ) ) - style_options = AF_STYLE_LTN2_DFLT; -#endif - /* * Glyphs (really code points) are assigned to scripts. Script * analysis is done lazily: For each glyph that passes through here, @@ -482,8 +473,8 @@ FT_Pos pp2x = loader->pp2.x; - loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); - loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); + loader->pp1.x = FT_PIX_ROUND( pp1x ); + loader->pp2.x = FT_PIX_ROUND( pp2x ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; @@ -594,7 +585,7 @@ * * XXX: Currently a crude adaption of the original algorithm. Do better? */ - FT_LOCAL_DEF( FT_Int32 ) + FT_LOCAL_DEF( FT_Fixed ) af_loader_compute_darkening( AF_Loader loader, FT_Face face, FT_Pos standard_width ) @@ -713,7 +704,7 @@ } /* Convert darken_amount from per 1000 em to true character space. */ - return af_fixedToInt( FT_DivFix( darken_amount, em_ratio ) ); + return FT_DivFix( darken_amount, em_ratio ); } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -75,7 +75,7 @@ FT_UInt gindex, FT_Int32 load_flags ); - FT_LOCAL_DEF( FT_Int32 ) + FT_LOCAL_DEF( FT_Fixed ) af_loader_compute_darkening( AF_Loader loader, FT_Face face, FT_Pos standard_width ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (body). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -48,7 +48,7 @@ int _af_debug_disable_blue_hints; /* we use a global object instead of a local one for debugging */ - AF_GlyphHintsRec _af_debug_hints_rec[1]; + static AF_GlyphHintsRec _af_debug_hints_rec[1]; void* _af_debug_hints = _af_debug_hints_rec; #endif @@ -148,7 +148,7 @@ if ( !af_style_classes[ss] ) { - FT_TRACE0(( "af_property_set: Invalid value %d for property `%s'\n", + FT_TRACE2(( "af_property_set: Invalid value %d for property `%s'\n", *fallback_script, property_name )); return FT_THROW( Invalid_Argument ); } @@ -190,35 +190,6 @@ return error; } -#ifdef AF_CONFIG_OPTION_USE_WARPER - else if ( !ft_strcmp( property_name, "warping" ) ) - { -#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES - if ( value_is_string ) - { - const char* s = (const char*)value; - long w = ft_strtol( s, NULL, 10 ); - - - if ( w == 0 ) - module->warping = 0; - else if ( w == 1 ) - module->warping = 1; - else - return FT_THROW( Invalid_Argument ); - } - else -#endif - { - FT_Bool* warping = (FT_Bool*)value; - - - module->warping = *warping; - } - - return error; - } -#endif /* AF_CONFIG_OPTION_USE_WARPER */ else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) { FT_Int* darken_params; @@ -307,7 +278,7 @@ return error; } - FT_TRACE0(( "af_property_set: missing property `%s'\n", + FT_TRACE2(( "af_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -322,9 +293,6 @@ AF_Module module = (AF_Module)ft_module; FT_UInt fallback_style = module->fallback_style; FT_UInt default_script = module->default_script; -#ifdef AF_CONFIG_OPTION_USE_WARPER - FT_Bool warping = module->warping; -#endif if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) @@ -371,17 +339,6 @@ return error; } -#ifdef AF_CONFIG_OPTION_USE_WARPER - else if ( !ft_strcmp( property_name, "warping" ) ) - { - FT_Bool* val = (FT_Bool*)value; - - - *val = warping; - - return error; - } -#endif /* AF_CONFIG_OPTION_USE_WARPER */ else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) { FT_Int* darken_params = module->darken_params; @@ -410,7 +367,7 @@ return error; } - FT_TRACE0(( "af_property_get: missing property `%s'\n", + FT_TRACE2(( "af_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -447,9 +404,6 @@ module->fallback_style = AF_STYLE_FALLBACK; module->default_script = AF_SCRIPT_DEFAULT; -#ifdef AF_CONFIG_OPTION_USE_WARPER - module->warping = 0; -#endif module->no_stem_darkening = TRUE; module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (specification). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -37,9 +37,6 @@ FT_UInt fallback_style; FT_UInt default_script; -#ifdef AF_CONFIG_OPTION_USE_WARPER - FT_Bool warping; -#endif FT_Bool no_stem_darkening; FT_Int darken_params[8]; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (body). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (specification). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter scripts (specification only). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (body). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -132,13 +132,24 @@ /* Convert a HarfBuzz script tag into the corresponding OpenType */ /* tag or tags -- some Indic scripts like Devanagari have an old */ /* and a new set of features. */ - hb_ot_tags_from_script( script, - &script_tags[0], - &script_tags[1] ); - - /* `hb_ot_tags_from_script' usually returns HB_OT_TAG_DEFAULT_SCRIPT */ - /* as the second tag. We change that to HB_TAG_NONE except for the */ - /* default script. */ + { + unsigned int tags_count = 3; + hb_tag_t tags[3]; + + + hb_ot_tags_from_script_and_language( script, + HB_LANGUAGE_INVALID, + &tags_count, + tags, + NULL, + NULL ); + script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE; + script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE; + script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE; + } + + /* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to */ + /* HB_TAG_NONE except for the default script. */ if ( default_script ) { if ( script_tags[0] == HB_TAG_NONE ) @@ -157,9 +168,6 @@ /* HarfBuzz maps them to `DFLT', which we don't want to handle here */ if ( script_tags[0] == HB_OT_TAG_DEFAULT_SCRIPT ) goto Exit; - - if ( script_tags[1] == HB_OT_TAG_DEFAULT_SCRIPT ) - script_tags[1] = HB_TAG_NONE; } gsub_lookups = hb_set_create(); @@ -173,9 +181,9 @@ if ( hb_set_is_empty( gsub_lookups ) ) goto Exit; /* nothing to do */ - FT_TRACE4(( "GSUB lookups (style `%s'):\n" - " ", + FT_TRACE4(( "GSUB lookups (style `%s'):\n", af_style_names[style_class->style] )); + FT_TRACE4(( " " )); #ifdef FT_DEBUG_LEVEL_TRACE count = 0; @@ -202,12 +210,13 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( !count ) FT_TRACE4(( " (none)" )); - FT_TRACE4(( "\n\n" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); #endif - FT_TRACE4(( "GPOS lookups (style `%s'):\n" - " ", + FT_TRACE4(( "GPOS lookups (style `%s'):\n", af_style_names[style_class->style] )); + FT_TRACE4(( " " )); gpos_lookups = hb_set_create(); hb_ot_layout_collect_lookups( face, @@ -242,7 +251,8 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( !count ) FT_TRACE4(( " (none)" )); - FT_TRACE4(( "\n\n" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); #endif /* @@ -353,8 +363,10 @@ { #ifdef FT_DEBUG_LEVEL_TRACE if ( !( count % 10 ) ) - FT_TRACE4(( "\n" - " " )); + { + FT_TRACE4(( "\n" )); + FT_TRACE4(( " " )); + } FT_TRACE4(( " %d", idx )); count++; @@ -376,9 +388,12 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( !count ) - FT_TRACE4(( "\n" - " (none)" )); - FT_TRACE4(( "\n\n" )); + { + FT_TRACE4(( "\n" )); + FT_TRACE4(( " (none)" )); + } + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); #endif Exit: diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (specification). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter styles (specification only). * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -299,15 +299,6 @@ AF_BLUE_STRINGSET_LATP, AF_COVERAGE_DEFAULT ) -#ifdef FT_OPTION_AUTOFIT2 - STYLE( ltn2_dflt, LTN2_DFLT, - "Latin 2 default style", - AF_WRITING_SYSTEM_LATIN2, - AF_SCRIPT_LATN, - AF_BLUE_STRINGSET_LATN, - AF_COVERAGE_DEFAULT ) -#endif - STYLE( lisu_dflt, LISU_DFLT, "Lisu default style", AF_WRITING_SYSTEM_LATIN, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auto-fitter types (specification only). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -92,63 +92,6 @@ FT_Pos threshold ); - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** A N G L E T Y P E S *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* - * The auto-fitter doesn't need a very high angular accuracy; - * this allows us to speed up some computations considerably with a - * light Cordic algorithm (see afangles.c). - */ - - typedef FT_Int AF_Angle; - - -#define AF_ANGLE_PI 256 -#define AF_ANGLE_2PI ( AF_ANGLE_PI * 2 ) -#define AF_ANGLE_PI2 ( AF_ANGLE_PI / 2 ) -#define AF_ANGLE_PI4 ( AF_ANGLE_PI / 4 ) - - -#if 0 - /* - * compute the angle of a given 2-D vector - */ - FT_LOCAL( AF_Angle ) - af_angle_atan( FT_Pos dx, - FT_Pos dy ); - - - /* - * compute `angle2 - angle1'; the result is always within - * the range [-AF_ANGLE_PI .. AF_ANGLE_PI - 1] - */ - FT_LOCAL( AF_Angle ) - af_angle_diff( AF_Angle angle1, - AF_Angle angle2 ); -#endif /* 0 */ - - -#define AF_ANGLE_DIFF( result, angle1, angle2 ) \ - FT_BEGIN_STMNT \ - AF_Angle _delta = (angle2) - (angle1); \ - \ - \ - while ( _delta <= -AF_ANGLE_PI ) \ - _delta += AF_ANGLE_2PI; \ - \ - while ( _delta > AF_ANGLE_PI ) \ - _delta -= AF_ANGLE_2PI; \ - \ - result = _delta; \ - FT_END_STMNT - - /* * opaque handle to glyph-specific hints -- see `afhints.h' for more * details @@ -172,7 +115,6 @@ #define AF_SCALER_FLAG_NO_HORIZONTAL 1U /* disable horizontal hinting */ #define AF_SCALER_FLAG_NO_VERTICAL 2U /* disable vertical hinting */ #define AF_SCALER_FLAG_NO_ADVANCE 4U /* disable advance hinting */ -#define AF_SCALER_FLAG_NO_WARPER 8U /* disable warper */ typedef struct AF_ScalerRec_ @@ -256,7 +198,6 @@ * outline according to the results of the glyph analyzer. */ -#define AFWRTSYS_H_ /* don't load header files */ #undef WRITING_SYSTEM #define WRITING_SYSTEM( ws, WS ) \ AF_WRITING_SYSTEM_ ## WS, @@ -265,14 +206,12 @@ typedef enum AF_WritingSystem_ { -#include "afwrtsys.h" +#include "afws-iter.h" AF_WRITING_SYSTEM_MAX /* do not remove */ } AF_WritingSystem; -#undef AFWRTSYS_H_ - typedef struct AF_WritingSystemClassRec_ { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afwarp.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afwarp.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afwarp.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afwarp.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,373 +0,0 @@ -/**************************************************************************** - * - * afwarp.c - * - * Auto-fitter warping algorithm (body). - * - * Copyright (C) 2006-2020 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.TXT. By continuing to use, modify, or distribute - * this file you indicate that you have read the license and - * understand and accept it fully. - * - */ - - - /* - * The idea of the warping code is to slightly scale and shift a glyph - * within a single dimension so that as much of its segments are aligned - * (more or less) on the grid. To find out the optimal scaling and - * shifting value, various parameter combinations are tried and scored. - */ - -#include "afwarp.h" - -#ifdef AF_CONFIG_OPTION_USE_WARPER - - /************************************************************************** - * - * The macro FT_COMPONENT is used in trace mode. It is an implicit - * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log - * messages during execution. - */ -#undef FT_COMPONENT -#define FT_COMPONENT afwarp - - - /* The weights cover the range 0/64 - 63/64 of a pixel. Obviously, */ - /* values around a half pixel (which means exactly between two grid */ - /* lines) gets the worst weight. */ -#if 1 - static const AF_WarpScore - af_warper_weights[64] = - { - 35, 32, 30, 25, 20, 15, 12, 10, 5, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -1, -2, -5, -8,-10,-10,-20,-20,-30,-30, - - -30,-30,-20,-20,-10,-10, -8, -5, -2, -1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 5, 10, 12, 15, 20, 25, 30, 32, - }; -#else - static const AF_WarpScore - af_warper_weights[64] = - { - 30, 20, 10, 5, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -1, -2, -2, -5, -5,-10,-10,-15,-20, - - -20,-15,-15,-10,-10, -5, -5, -2, -2, -1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 5, 10, 20, - }; -#endif - - - /* Score segments for a given `scale' and `delta' in the range */ - /* `xx1' to `xx2', and store the best result in `warper'. If */ - /* the new best score is equal to the old one, prefer the */ - /* value with a smaller distortion (around `base_distort'). */ - - static void - af_warper_compute_line_best( AF_Warper warper, - FT_Fixed scale, - FT_Pos delta, - FT_Pos xx1, - FT_Pos xx2, - AF_WarpScore base_distort, - AF_Segment segments, - FT_Int num_segments ) - { - FT_Int idx_min, idx_max, idx0; - FT_Int nn; - AF_WarpScore scores[65]; - - - for ( nn = 0; nn < 65; nn++ ) - scores[nn] = 0; - - idx0 = xx1 - warper->t1; - - /* compute minimum and maximum indices */ - { - FT_Pos xx1min = warper->x1min; - FT_Pos xx1max = warper->x1max; - FT_Pos w = xx2 - xx1; - - - if ( xx1min + w < warper->x2min ) - xx1min = warper->x2min - w; - - if ( xx1max + w > warper->x2max ) - xx1max = warper->x2max - w; - - idx_min = xx1min - warper->t1; - idx_max = xx1max - warper->t1; - - if ( idx_min < 0 || idx_min > idx_max || idx_max > 64 ) - { - FT_TRACE5(( "invalid indices:\n" - " min=%d max=%d, xx1=%ld xx2=%ld,\n" - " x1min=%ld x1max=%ld, x2min=%ld x2max=%ld\n", - idx_min, idx_max, xx1, xx2, - warper->x1min, warper->x1max, - warper->x2min, warper->x2max )); - return; - } - } - - for ( nn = 0; nn < num_segments; nn++ ) - { - FT_Pos len = segments[nn].max_coord - segments[nn].min_coord; - FT_Pos y0 = FT_MulFix( segments[nn].pos, scale ) + delta; - FT_Pos y = y0 + ( idx_min - idx0 ); - FT_Int idx; - - - /* score the length of the segments for the given range */ - for ( idx = idx_min; idx <= idx_max; idx++, y++ ) - scores[idx] += af_warper_weights[y & 63] * len; - } - - /* find best score */ - { - FT_Int idx; - - - for ( idx = idx_min; idx <= idx_max; idx++ ) - { - AF_WarpScore score = scores[idx]; - AF_WarpScore distort = base_distort + ( idx - idx0 ); - - - if ( score > warper->best_score || - ( score == warper->best_score && - distort < warper->best_distort ) ) - { - warper->best_score = score; - warper->best_distort = distort; - warper->best_scale = scale; - warper->best_delta = delta + ( idx - idx0 ); - } - } - } - } - - - /* Compute optimal scaling and delta values for a given glyph and */ - /* dimension. */ - - FT_LOCAL_DEF( void ) - af_warper_compute( AF_Warper warper, - AF_GlyphHints hints, - AF_Dimension dim, - FT_Fixed *a_scale, - FT_Pos *a_delta ) - { - AF_AxisHints axis; - AF_Point points; - - FT_Fixed org_scale; - FT_Pos org_delta; - - FT_Int nn, num_points, num_segments; - FT_Int X1, X2; - FT_Int w; - - AF_WarpScore base_distort; - AF_Segment segments; - - - /* get original scaling transformation */ - if ( dim == AF_DIMENSION_VERT ) - { - org_scale = hints->y_scale; - org_delta = hints->y_delta; - } - else - { - org_scale = hints->x_scale; - org_delta = hints->x_delta; - } - - warper->best_scale = org_scale; - warper->best_delta = org_delta; - warper->best_score = FT_INT_MIN; - warper->best_distort = 0; - - axis = &hints->axis[dim]; - segments = axis->segments; - num_segments = axis->num_segments; - points = hints->points; - num_points = hints->num_points; - - *a_scale = org_scale; - *a_delta = org_delta; - - /* get X1 and X2, minimum and maximum in original coordinates */ - if ( num_segments < 1 ) - return; - -#if 1 - X1 = X2 = points[0].fx; - for ( nn = 1; nn < num_points; nn++ ) - { - FT_Int X = points[nn].fx; - - - if ( X < X1 ) - X1 = X; - if ( X > X2 ) - X2 = X; - } -#else - X1 = X2 = segments[0].pos; - for ( nn = 1; nn < num_segments; nn++ ) - { - FT_Int X = segments[nn].pos; - - - if ( X < X1 ) - X1 = X; - if ( X > X2 ) - X2 = X; - } -#endif - - if ( X1 >= X2 ) - return; - - warper->x1 = FT_MulFix( X1, org_scale ) + org_delta; - warper->x2 = FT_MulFix( X2, org_scale ) + org_delta; - - warper->t1 = AF_WARPER_FLOOR( warper->x1 ); - warper->t2 = AF_WARPER_CEIL( warper->x2 ); - - /* examine a half pixel wide range around the maximum coordinates */ - warper->x1min = warper->x1 & ~31; - warper->x1max = warper->x1min + 32; - warper->x2min = warper->x2 & ~31; - warper->x2max = warper->x2min + 32; - - if ( warper->x1max > warper->x2 ) - warper->x1max = warper->x2; - - if ( warper->x2min < warper->x1 ) - warper->x2min = warper->x1; - - warper->w0 = warper->x2 - warper->x1; - - if ( warper->w0 <= 64 ) - { - warper->x1max = warper->x1; - warper->x2min = warper->x2; - } - - /* examine (at most) a pixel wide range around the natural width */ - warper->wmin = warper->x2min - warper->x1max; - warper->wmax = warper->x2max - warper->x1min; - -#if 1 - /* some heuristics to reduce the number of widths to be examined */ - { - int margin = 16; - - - if ( warper->w0 <= 128 ) - { - margin = 8; - if ( warper->w0 <= 96 ) - margin = 4; - } - - if ( warper->wmin < warper->w0 - margin ) - warper->wmin = warper->w0 - margin; - - if ( warper->wmax > warper->w0 + margin ) - warper->wmax = warper->w0 + margin; - } - - if ( warper->wmin < warper->w0 * 3 / 4 ) - warper->wmin = warper->w0 * 3 / 4; - - if ( warper->wmax > warper->w0 * 5 / 4 ) - warper->wmax = warper->w0 * 5 / 4; -#else - /* no scaling, just translation */ - warper->wmin = warper->wmax = warper->w0; -#endif - - for ( w = warper->wmin; w <= warper->wmax; w++ ) - { - FT_Fixed new_scale; - FT_Pos new_delta; - FT_Pos xx1, xx2; - - - /* compute min and max positions for given width, */ - /* assuring that they stay within the coordinate ranges */ - xx1 = warper->x1; - xx2 = warper->x2; - if ( w >= warper->w0 ) - { - xx1 -= w - warper->w0; - if ( xx1 < warper->x1min ) - { - xx2 += warper->x1min - xx1; - xx1 = warper->x1min; - } - } - else - { - xx1 -= w - warper->w0; - if ( xx1 > warper->x1max ) - { - xx2 -= xx1 - warper->x1max; - xx1 = warper->x1max; - } - } - - if ( xx1 < warper->x1 ) - base_distort = warper->x1 - xx1; - else - base_distort = xx1 - warper->x1; - - if ( xx2 < warper->x2 ) - base_distort += warper->x2 - xx2; - else - base_distort += xx2 - warper->x2; - - /* give base distortion a greater weight while scoring */ - base_distort *= 10; - - new_scale = org_scale + FT_DivFix( w - warper->w0, X2 - X1 ); - new_delta = xx1 - FT_MulFix( X1, new_scale ); - - af_warper_compute_line_best( warper, new_scale, new_delta, xx1, xx2, - base_distort, - segments, num_segments ); - } - - { - FT_Fixed best_scale = warper->best_scale; - FT_Pos best_delta = warper->best_delta; - - - hints->xmin_delta = FT_MulFix( X1, best_scale - org_scale ) - + best_delta; - hints->xmax_delta = FT_MulFix( X2, best_scale - org_scale ) - + best_delta; - - *a_scale = best_scale; - *a_delta = best_delta; - } - } - -#else /* !AF_CONFIG_OPTION_USE_WARPER */ - - /* ANSI C doesn't like empty source files */ - typedef int _af_warp_dummy; - -#endif /* !AF_CONFIG_OPTION_USE_WARPER */ - -/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afwarp.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afwarp.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afwarp.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afwarp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/**************************************************************************** - * - * afwarp.h - * - * Auto-fitter warping algorithm (specification). - * - * Copyright (C) 2006-2020 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.TXT. By continuing to use, modify, or distribute - * this file you indicate that you have read the license and - * understand and accept it fully. - * - */ - - -#ifndef AFWARP_H_ -#define AFWARP_H_ - -#include "afhints.h" - -FT_BEGIN_HEADER - -#define AF_WARPER_SCALE - -#define AF_WARPER_FLOOR( x ) ( (x) & ~FT_TYPEOF( x )63 ) -#define AF_WARPER_CEIL( x ) AF_WARPER_FLOOR( (x) + 63 ) - - - typedef FT_Int32 AF_WarpScore; - - typedef struct AF_WarperRec_ - { - FT_Pos x1, x2; - FT_Pos t1, t2; - FT_Pos x1min, x1max; - FT_Pos x2min, x2max; - FT_Pos w0, wmin, wmax; - - FT_Fixed best_scale; - FT_Pos best_delta; - AF_WarpScore best_score; - AF_WarpScore best_distort; - - } AF_WarperRec, *AF_Warper; - - -#ifdef AF_CONFIG_OPTION_USE_WARPER - FT_LOCAL( void ) - af_warper_compute( AF_Warper warper, - AF_GlyphHints hints, - AF_Dimension dim, - FT_Fixed *a_scale, - FT_Pos *a_delta ); -#endif - - -FT_END_HEADER - - -#endif /* AFWARP_H_ */ - - -/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afwrtsys.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afwrtsys.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afwrtsys.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afwrtsys.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/**************************************************************************** - * - * afwrtsys.h - * - * Auto-fitter writing systems (specification only). - * - * Copyright (C) 2013-2020 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.TXT. By continuing to use, modify, or distribute - * this file you indicate that you have read the license and - * understand and accept it fully. - * - */ - - -#ifndef AFWRTSYS_H_ -#define AFWRTSYS_H_ - - /* Since preprocessor directives can't create other preprocessor */ - /* directives, we have to include the header files manually. */ - -#include "afdummy.h" -#include "aflatin.h" -#include "afcjk.h" -#include "afindic.h" -#ifdef FT_OPTION_AUTOFIT2 -#include "aflatin2.h" -#endif - -#endif /* AFWRTSYS_H_ */ - - - /* The following part can be included multiple times. */ - /* Define `WRITING_SYSTEM' as needed. */ - - - /* Add new writing systems here. The arguments are the writing system */ - /* name in lowercase and uppercase, respectively. */ - - WRITING_SYSTEM( dummy, DUMMY ) - WRITING_SYSTEM( latin, LATIN ) - WRITING_SYSTEM( cjk, CJK ) - WRITING_SYSTEM( indic, INDIC ) -#ifdef FT_OPTION_AUTOFIT2 - WRITING_SYSTEM( latin2, LATIN2 ) -#endif - - -/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,33 @@ +/**************************************************************************** + * + * afws-decl.h + * + * Auto-fitter writing system declarations (specification only). + * + * Copyright (C) 2013-2022 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFWS_DECL_H_ +#define AFWS_DECL_H_ + + /* Since preprocessor directives can't create other preprocessor */ + /* directives, we have to include the header files manually. */ + +#include "afdummy.h" +#include "aflatin.h" +#include "afcjk.h" +#include "afindic.h" + +#endif /* AFWS_DECL_H_ */ + + +/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * afws-iter.h + * + * Auto-fitter writing systems iterator (specification only). + * + * Copyright (C) 2013-2022 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + /* This header may be included multiple times. */ + /* Define `WRITING_SYSTEM' as needed. */ + + + /* Add new writing systems here. The arguments are the writing system */ + /* name in lowercase and uppercase, respectively. */ + + WRITING_SYSTEM( dummy, DUMMY ) + WRITING_SYSTEM( latin, LATIN ) + WRITING_SYSTEM( cjk, CJK ) + WRITING_SYSTEM( indic, INDIC ) + + +/* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Quick computation of advance widths (body). * - * Copyright (C) 2008-2020 by + * Copyright (C) 2008-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftbase.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftbase.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftbase.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftbase.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Private functions used in the `base' module (specification). * - * Copyright (C) 2008-2020 by + * Copyright (C) 2008-2022 by * David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. * * This file is part of the FreeType project, and may only be used, @@ -28,6 +28,7 @@ FT_DECLARE_GLYPH( ft_bitmap_glyph_class ) FT_DECLARE_GLYPH( ft_outline_glyph_class ) + FT_DECLARE_GLYPH( ft_svg_glyph_class ) #ifdef FT_CONFIG_OPTION_MAC_FONTS diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType bbox computation (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (body). * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -112,10 +112,10 @@ target_size = (FT_ULong)target_pitch * target->rows; if ( target_size != size ) - (void)FT_QREALLOC( target->buffer, target_size, size ); + FT_MEM_QREALLOC( target->buffer, target_size, size ); } else - (void)FT_QALLOC( target->buffer, size ); + FT_MEM_QALLOC( target->buffer, size ); if ( !error ) { @@ -480,7 +480,7 @@ * A gamma of 2.2 is fair to assume. And then, we need to * undo the premultiplication too. * - * https://accessibility.kde.org/hsl-adjusted.php + * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html#SideNotes * * We do the computation with integers only, applying a gamma of 2.0. * We guarantee 32-bit arithmetic to avoid overflow but the resulting @@ -488,9 +488,9 @@ * */ - l = ( 4732UL /* 0.0722 * 65536 */ * bgra[0] * bgra[0] + - 46871UL /* 0.7152 * 65536 */ * bgra[1] * bgra[1] + - 13933UL /* 0.2126 * 65536 */ * bgra[2] * bgra[2] ) >> 16; + l = ( 4731UL /* 0.072186 * 65536 */ * bgra[0] * bgra[0] + + 46868UL /* 0.715158 * 65536 */ * bgra[1] * bgra[1] + + 13937UL /* 0.212656 * 65536 */ * bgra[2] * bgra[2] ) >> 16; /* * Final transparency can be determined as follows. @@ -907,8 +907,8 @@ final_rows = ( final_ury - final_lly ) >> 6; #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( "FT_Bitmap_Blend:\n" - " source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + FT_TRACE5(( "FT_Bitmap_Blend:\n" )); + FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", source_llx / 64, source_lly / 64, source_urx / 64, source_ury / 64, source_->width, source_->rows )); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Arithmetic computations (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -45,7 +45,7 @@ /* we need to emulate a 64-bit data type if a real one isn't available */ -#ifndef FT_LONG64 +#ifndef FT_INT64 typedef struct FT_Int64_ { @@ -54,7 +54,7 @@ } FT_Int64; -#endif /* !FT_LONG64 */ +#endif /* !FT_INT64 */ /************************************************************************** @@ -79,7 +79,7 @@ FT_END_STMNT /* The following three functions are available regardless of whether */ - /* FT_LONG64 is defined. */ + /* FT_INT64 is defined. */ /* documentation is in freetype.h */ @@ -109,7 +109,7 @@ #ifndef FT_MSB - FT_BASE_DEF ( FT_Int ) + FT_BASE_DEF( FT_Int ) FT_MSB( FT_UInt32 z ) { FT_Int shift = 0; @@ -164,7 +164,7 @@ } -#ifdef FT_LONG64 +#ifdef FT_INT64 /* documentation is in freetype.h */ @@ -272,7 +272,7 @@ } -#else /* !FT_LONG64 */ +#else /* !FT_INT64 */ static void @@ -651,7 +651,7 @@ } -#endif /* !FT_LONG64 */ +#endif /* !FT_INT64 */ /* documentation is in ftglyph.h */ @@ -985,7 +985,7 @@ /* we silently ignore overflow errors since such large values */ /* lead to even more (harmless) rendering errors later on */ -#ifdef FT_LONG64 +#ifdef FT_INT64 FT_Int64 delta = SUB_INT64( MUL_INT64( in_x, out_y ), MUL_INT64( in_y, out_x ) ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftcid.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftcid.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftcid.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftcid.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information. * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Memory debugger (body). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -302,46 +302,6 @@ } - static FT_MemTable - ft_mem_table_new( FT_Memory memory ) - { - FT_MemTable table; - - - table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); - if ( !table ) - goto Exit; - - FT_ZERO( table ); - - table->size = FT_MEM_SIZE_MIN; - table->nodes = 0; - - table->memory = memory; - - table->memory_user = memory->user; - - table->alloc = memory->alloc; - table->realloc = memory->realloc; - table->free = memory->free; - - table->buckets = (FT_MemNode *) - memory->alloc( - memory, - table->size * (FT_Long)sizeof ( FT_MemNode ) ); - if ( table->buckets ) - FT_ARRAY_ZERO( table->buckets, table->size ); - else - { - memory->free( memory, table ); - table = NULL; - } - - Exit: - return table; - } - - static void ft_mem_table_destroy( FT_MemTable table ) { @@ -350,8 +310,6 @@ FT_Long leaks = 0; - FT_DumpMemory( table->memory ); - /* remove all blocks from the table, revealing leaked ones */ for ( i = 0; i < table->size; i++ ) { @@ -413,8 +371,6 @@ printf( "FreeType: maximum memory footprint = %ld\n", table->alloc_max ); - ft_mem_table_free( table, table ); - if ( leak_count > 0 ) ft_mem_debug_panic( "FreeType: %ld bytes of memory leaked in %ld blocks\n", @@ -821,17 +777,30 @@ } - extern FT_Int + extern void ft_mem_debug_init( FT_Memory memory ) { FT_MemTable table; - FT_Int result = 0; - if ( ft_getenv( "FT2_DEBUG_MEMORY" ) ) + if ( !ft_getenv( "FT2_DEBUG_MEMORY" ) ) + return; + + table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); + + if ( table ) { - table = ft_mem_table_new( memory ); - if ( table ) + FT_ZERO( table ); + + table->memory = memory; + table->memory_user = memory->user; + table->alloc = memory->alloc; + table->realloc = memory->realloc; + table->free = memory->free; + + ft_mem_table_resize( table ); + + if ( table->size ) { const char* p; @@ -876,28 +845,31 @@ if ( keep_alive > 0 ) table->keep_alive = 1; } - - result = 1; } + else + memory->free( memory, table ); } - return result; } extern void ft_mem_debug_done( FT_Memory memory ) { - FT_MemTable table = (FT_MemTable)memory->user; + if ( memory->free == ft_mem_debug_free ) + { + FT_MemTable table = (FT_MemTable)memory->user; - if ( table ) - { + FT_DumpMemory( memory ); + + ft_mem_table_destroy( table ); + memory->free = table->free; memory->realloc = table->realloc; memory->alloc = table->alloc; + memory->user = table->memory_user; - ft_mem_table_destroy( table ); - memory->user = NULL; + memory->free( memory, table ); } } @@ -922,11 +894,9 @@ extern void FT_DumpMemory( FT_Memory memory ) { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) + if ( memory->free == ft_mem_debug_free ) { + FT_MemTable table = (FT_MemTable)memory->user; FT_MemSource* bucket = table->sources; FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS; FT_MemSource* sources; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Debugging and logging component (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -42,7 +42,53 @@ #include +#include #include +#include + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Variables used to control logging. + * + * 1. `ft_default_trace_level` stores the value of trace levels, which are + * provided to FreeType using the `FT2_DEBUG` environment variable. + * + * 2. `ft_fileptr` stores the `FILE*` handle. + * + * 3. `ft_component` is a string that holds the name of `FT_COMPONENT`. + * + * 4. The flag `ft_component_flag` prints the name of `FT_COMPONENT` along + * with the actual log message if set to true. + * + * 5. The flag `ft_timestamp_flag` prints time along with the actual log + * message if set to ture. + * + * 6. `ft_have_newline_char` is used to differentiate between a log + * message with and without a trailing newline character. + * + * 7. `ft_custom_trace_level` stores the custom trace level value, which + * is provided by the user at run-time. + * + * We use `static` to avoid 'unused variable' warnings. + * + */ + static const char* ft_default_trace_level = NULL; + static FILE* ft_fileptr = NULL; + static const char* ft_component = NULL; + static FT_Bool ft_component_flag = FALSE; + static FT_Bool ft_timestamp_flag = FALSE; + static FT_Bool ft_have_newline_char = TRUE; + static const char* ft_custom_trace_level = NULL; + + /* declared in ftdebug.h */ + + dlg_handler ft_default_log_handler = NULL; + FT_Custom_Log_Handler custom_output_handler = NULL; + +#endif /* FT_DEBUG_LOGGING */ #ifdef FT_DEBUG_LEVEL_ERROR @@ -106,7 +152,6 @@ #endif /* FT_DEBUG_LEVEL_ERROR */ - #ifdef FT_DEBUG_LEVEL_TRACE /* array of trace levels, initialized to 0; */ @@ -195,9 +240,18 @@ FT_BASE_DEF( void ) ft_debug_init( void ) { - const char* ft2_debug = ft_getenv( "FT2_DEBUG" ); + const char* ft2_debug = NULL; +#ifdef FT_DEBUG_LOGGING + if ( ft_custom_trace_level != NULL ) + ft2_debug = ft_custom_trace_level; + else + ft2_debug = ft_default_trace_level; +#else + ft2_debug = ft_getenv( "FT2_DEBUG" ); +#endif + if ( ft2_debug ) { const char* p = ft2_debug; @@ -210,6 +264,49 @@ if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' ) continue; +#ifdef FT_DEBUG_LOGGING + + /* check extra arguments for logging */ + if ( *p == '-' ) + { + const char* r = ++p; + + + if ( *r == 'v' ) + { + const char* s = ++r; + + + ft_component_flag = TRUE; + + if ( *s == 't' ) + { + ft_timestamp_flag = TRUE; + p++; + } + + p++; + } + + else if ( *r == 't' ) + { + const char* s = ++r; + + + ft_timestamp_flag = TRUE; + + if ( *s == 'v' ) + { + ft_component_flag = TRUE; + p++; + } + + p++; + } + } + +#endif /* FT_DEBUG_LOGGING */ + /* read toggle name, followed by ':' */ q = p; while ( *p && *p != ':' ) @@ -311,8 +408,237 @@ /* nothing */ } - #endif /* !FT_DEBUG_LEVEL_TRACE */ +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Initialize and de-initialize 'dlg' library. + * + */ + + FT_BASE_DEF( void ) + ft_logging_init( void ) + { + ft_default_log_handler = ft_log_handler; + ft_default_trace_level = ft_getenv( "FT2_DEBUG" ); + + if ( ft_getenv( "FT_LOGGING_FILE" ) ) + ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" ); + else + ft_fileptr = stderr; + + ft_debug_init(); + + /* Set the default output handler for 'dlg'. */ + dlg_set_handler( ft_default_log_handler, NULL ); + } + + + FT_BASE_DEF( void ) + ft_logging_deinit( void ) + { + if ( ft_fileptr != stderr ) + ft_fclose( ft_fileptr ); + } + + + /************************************************************************** + * + * An output log handler for FreeType. + * + */ + FT_BASE_DEF( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ) + { + char features_buf[128]; + char* bufp = features_buf; + + FT_UNUSED( data ); + + + if ( ft_have_newline_char ) + { + const char* features = NULL; + size_t features_length = 0; + + +#define FEATURES_TIMESTAMP "[%h:%m] " +#define FEATURES_COMPONENT "[%t] " +#define FEATURES_TIMESTAMP_COMPONENT "[%h:%m %t] " + + if ( ft_timestamp_flag && ft_component_flag ) + { + features = FEATURES_TIMESTAMP_COMPONENT; + features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT ); + } + else if ( ft_timestamp_flag ) + { + features = FEATURES_TIMESTAMP; + features_length = sizeof ( FEATURES_TIMESTAMP ); + } + else if ( ft_component_flag ) + { + features = FEATURES_COMPONENT; + features_length = sizeof ( FEATURES_COMPONENT ); + } + + if ( ft_component_flag || ft_timestamp_flag ) + { + ft_strncpy( features_buf, features, features_length ); + bufp += features_length - 1; + } + + if ( ft_component_flag ) + { + size_t tag_length = ft_strlen( *origin->tags ); + size_t i; + + + /* To vertically align tracing messages we compensate the */ + /* different FT_COMPONENT string lengths by inserting an */ + /* appropriate amount of space characters. */ + for ( i = 0; + i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length; + i++ ) + *bufp++ = ' '; + } + } + + /* Finally add the format string for the tracing message. */ + *bufp++ = '%'; + *bufp++ = 'c'; + *bufp = '\0'; + + dlg_generic_outputf_stream( ft_fileptr, + (const char*)features_buf, + origin, + string, + dlg_default_output_styles, + true ); + + if ( ft_strrchr( string, '\n' ) ) + ft_have_newline_char = TRUE; + else + ft_have_newline_char = FALSE; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_add_tag( const char* tag ) + { + ft_component = tag; + + dlg_add_tag( tag, NULL ); + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_remove_tag( const char* tag ) + { + dlg_remove_tag( tag, NULL ); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = level; + + ft_debug_init(); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = NULL; + + ft_debug_init(); + } + + + /************************************************************************** + * + * Functions to handle a custom log handler. + * + */ + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + custom_output_handler = handler; + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + custom_output_handler = NULL; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + FT_Logging_Callback( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + custom_output_handler( ft_component, fmt, ap ); + va_end( ap ); + } + +#else /* !FT_DEBUG_LOGGING */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + FT_UNUSED( level ); + } + + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + /* nothing */ + } + + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + FT_UNUSED( handler ); + } + + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + /* nothing */ + } + +#endif /* !FT_DEBUG_LOGGING */ + + /* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType utility file for font formats (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType utility file to access FSType data (body). * - * Copyright (C) 2008-2020 by + * Copyright (C) 2008-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Access of TrueType's `gasp' table (body). * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType glyph loader (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -34,6 +34,7 @@ #include #include #include +#include #include "ftbase.h" @@ -277,6 +278,240 @@ ) +#ifdef FT_CONFIG_OPTION_SVG + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_SvgGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_init( FT_Glyph svg_glyph, + FT_GlyphSlot slot ) + { + FT_ULong doc_length; + FT_SVG_Document document; + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_GLYPH( glyph )->library->memory; + + + if ( slot->format != FT_GLYPH_FORMAT_SVG ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + if ( slot->other == NULL ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + document = (FT_SVG_Document)slot->other; + + if ( document->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + /* allocate a new document */ + doc_length = document->svg_document_length; + if ( FT_QALLOC( glyph->svg_document, doc_length ) ) + goto Exit; + glyph->svg_document_length = doc_length; + + glyph->glyph_index = slot->glyph_index; + + glyph->metrics = document->metrics; + glyph->units_per_EM = document->units_per_EM; + + glyph->start_glyph_id = document->start_glyph_id; + glyph->end_glyph_id = document->end_glyph_id; + + glyph->transform = document->transform; + glyph->delta = document->delta; + + /* copy the document into glyph */ + FT_MEM_COPY( glyph->svg_document, document->svg_document, doc_length ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_svg_glyph_done( FT_Glyph svg_glyph ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + FT_Memory memory = svg_glyph->library->memory; + + + /* just free the memory */ + FT_FREE( glyph->svg_document ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_copy( FT_Glyph svg_source, + FT_Glyph svg_target ) + { + FT_SvgGlyph source = (FT_SvgGlyph)svg_source; + FT_SvgGlyph target = (FT_SvgGlyph)svg_target; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_GLYPH( source )->library->memory; + + + if ( svg_source->format != FT_GLYPH_FORMAT_SVG ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + if ( source->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + target->glyph_index = source->glyph_index; + + target->svg_document_length = source->svg_document_length; + + target->metrics = source->metrics; + target->units_per_EM = source->units_per_EM; + + target->start_glyph_id = source->start_glyph_id; + target->end_glyph_id = source->end_glyph_id; + + target->transform = source->transform; + target->delta = source->delta; + + /* allocate space for the SVG document */ + if ( FT_QALLOC( target->svg_document, target->svg_document_length ) ) + goto Exit; + + /* copy the document */ + FT_MEM_COPY( target->svg_document, + source->svg_document, + target->svg_document_length ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_svg_glyph_transform( FT_Glyph svg_glyph, + const FT_Matrix* _matrix, + const FT_Vector* _delta ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + FT_Matrix* matrix = (FT_Matrix*)_matrix; + FT_Vector* delta = (FT_Vector*)_delta; + + FT_Matrix tmp_matrix; + FT_Vector tmp_delta; + + FT_Matrix a, b; + FT_Pos x, y; + + + if ( !matrix ) + { + tmp_matrix.xx = 0x10000; + tmp_matrix.xy = 0; + tmp_matrix.yx = 0; + tmp_matrix.yy = 0x10000; + + matrix = &tmp_matrix; + } + + if ( !delta ) + { + tmp_delta.x = 0; + tmp_delta.y = 0; + + delta = &tmp_delta; + } + + a = glyph->transform; + b = *matrix; + FT_Matrix_Multiply( &b, &a ); + + x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, glyph->delta.x ), + FT_MulFix( matrix->xy, glyph->delta.y ) ), + delta->x ); + y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, glyph->delta.x ), + FT_MulFix( matrix->yy, glyph->delta.y ) ), + delta->y ); + + glyph->delta.x = x; + glyph->delta.y = y; + + glyph->transform = a; + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_prepare( FT_Glyph svg_glyph, + FT_GlyphSlot slot ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = svg_glyph->library->memory; + + FT_SVG_Document document = NULL; + + + if ( FT_NEW( document ) ) + return error; + + document->svg_document = glyph->svg_document; + document->svg_document_length = glyph->svg_document_length; + + document->metrics = glyph->metrics; + document->units_per_EM = glyph->units_per_EM; + + document->start_glyph_id = glyph->start_glyph_id; + document->end_glyph_id = glyph->end_glyph_id; + + document->transform = glyph->transform; + document->delta = glyph->delta; + + slot->format = FT_GLYPH_FORMAT_SVG; + slot->glyph_index = glyph->glyph_index; + slot->other = document; + + return error; + } + + + FT_DEFINE_GLYPH( + ft_svg_glyph_class, + + sizeof ( FT_SvgGlyphRec ), + FT_GLYPH_FORMAT_SVG, + + ft_svg_glyph_init, /* FT_Glyph_InitFunc glyph_init */ + ft_svg_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ + ft_svg_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ + ft_svg_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ + NULL, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + ft_svg_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + +#endif /* FT_CONFIG_OPTION_SVG */ + + /*************************************************************************/ /*************************************************************************/ /**** ****/ @@ -377,6 +612,12 @@ else if ( format == FT_GLYPH_FORMAT_OUTLINE ) clazz = &ft_outline_glyph_class; +#ifdef FT_CONFIG_OPTION_SVG + /* if it is an SVG glyph */ + else if ( format == FT_GLYPH_FORMAT_SVG ) + clazz = &ft_svg_glyph_class; +#endif + else { /* try to find a renderer that supports the glyph image format */ @@ -453,9 +694,9 @@ /* documentation is in ftglyph.h */ FT_EXPORT_DEF( FT_Error ) - FT_Glyph_Transform( FT_Glyph glyph, - FT_Matrix* matrix, - FT_Vector* delta ) + FT_Glyph_Transform( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ) { FT_Error error = FT_Err_Ok; @@ -533,10 +774,10 @@ /* documentation is in ftglyph.h */ FT_EXPORT_DEF( FT_Error ) - FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, - FT_Render_Mode render_mode, - FT_Vector* origin, - FT_Bool destroy ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + const FT_Vector* origin, + FT_Bool destroy ) { FT_GlyphSlotRec dummy; FT_GlyphSlot_InternalRec dummy_internal; @@ -585,7 +826,7 @@ #if 1 /* if `origin' is set, translate the glyph image */ if ( origin ) - FT_Glyph_Transform( glyph, 0, origin ); + FT_Glyph_Transform( glyph, NULL, origin ); #else FT_UNUSED( origin ); #endif @@ -595,6 +836,16 @@ if ( !error ) error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); +#ifdef FT_CONFIG_OPTION_SVG + if ( clazz == &ft_svg_glyph_class ) + { + FT_Memory memory = library->memory; + + + FT_FREE( dummy.other ); + } +#endif + #if 1 if ( !destroy && origin ) { @@ -603,7 +854,7 @@ v.x = -origin->x; v.y = -origin->y; - FT_Glyph_Transform( glyph, 0, &v ); + FT_Glyph_Transform( glyph, NULL, &v ); } #endif diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/fthash.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/fthash.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/fthash.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/fthash.c 2022-07-14 08:05:38.000000000 +0000 @@ -243,7 +243,7 @@ nn = *bp; if ( !nn ) { - if ( FT_NEW( nn ) ) + if ( FT_QNEW( nn ) ) goto Exit; *bp = nn; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftinit.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftinit.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftinit.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftinit.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType initialization layer (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -202,6 +202,10 @@ FT_Memory memory; +#ifdef FT_DEBUG_LOGGING + ft_logging_init(); +#endif + /* check of `alibrary' delayed to `FT_New_Library' */ /* First of all, allocate a new system object -- this function is part */ @@ -248,6 +252,10 @@ /* discard memory manager */ FT_Done_Memory( memory ); +#ifdef FT_DEBUG_LOGGING + ft_logging_deinit(); +#endif + return FT_Err_Ok; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType API for color filtering of subpixel bitmap glyphs (body). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -32,7 +32,7 @@ /* add padding according to filter weights */ - FT_BASE_DEF (void) + FT_BASE_DEF( void ) ft_lcd_padding( FT_BBox* cbox, FT_GlyphSlot slot, FT_Render_Mode mode ) @@ -357,7 +357,7 @@ FT_EXPORT_DEF( FT_Error ) FT_Library_SetLcdGeometry( FT_Library library, - FT_Vector* sub ) + FT_Vector sub[3] ) { FT_UNUSED( library ); FT_UNUSED( sub ); @@ -368,7 +368,7 @@ #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ /* add padding to accommodate outline shifts */ - FT_BASE_DEF (void) + FT_BASE_DEF( void ) ft_lcd_padding( FT_BBox* cbox, FT_GlyphSlot slot, FT_Render_Mode mode ) @@ -428,7 +428,7 @@ ft_memcpy( library->lcd_geometry, sub, 3 * sizeof( FT_Vector ) ); - return FT_THROW( Unimplemented_Feature ); + return FT_Err_Ok; } #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftmac.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftmac.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftmac.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftmac.c 2022-07-14 08:05:38.000000000 +0000 @@ -8,7 +8,7 @@ * This file is for Mac OS X only; see builds/mac/ftoldmac.c for * classic platforms built by MPW. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -105,7 +105,7 @@ /* Don't want warnings about our own use of deprecated functions. */ #define FT_DEPRECATED_ATTRIBUTE -#include FT_MAC_H +#include #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */ #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault @@ -560,7 +560,7 @@ if ( lwfn_file_name[0] ) { err = lookup_lwfn_by_fond( pathname, lwfn_file_name, - buff, sizeof ( buff ) ); + buff, sizeof ( buff ) ); if ( !err ) have_lwfn = 1; } @@ -631,7 +631,7 @@ old_total_size = total_size; } - if ( FT_ALLOC( buffer, (FT_Long)total_size ) ) + if ( FT_QALLOC( buffer, (FT_Long)total_size ) ) goto Error; /* Second pass: append all POST data to the buffer, add PFB fields. */ @@ -752,7 +752,7 @@ if ( FT_MAC_RFORK_MAX_LEN < sfnt_size ) return FT_THROW( Array_Too_Large ); - if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) ) + if ( FT_QALLOC( sfnt_data, (FT_Long)sfnt_size ) ) { ReleaseResource( sfnt ); return error; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftmm.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftmm.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftmm.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftmm.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Multiple Master font support (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType private base classes (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,7 @@ #include #include /* for SFNT_Load_Table_Func */ #include /* for PS_Driver */ +#include #include #include @@ -78,6 +80,9 @@ #pragma warning( pop ) #endif + /* This array must stay in sync with the @FT_Pixel_Mode enumeration */ + /* (in file `ftimage.h`). */ + static const char* const pixel_modes[] = { "none", @@ -87,7 +92,8 @@ "gray 4-bit bitmap", "LCD 8-bit bitmap", "vertical LCD 8-bit bitmap", - "BGRA 32-bit color image bitmap" + "BGRA 32-bit color image bitmap", + "SDF 8-bit bitmap" }; #endif /* FT_DEBUG_LEVEL_TRACE */ @@ -193,6 +199,7 @@ FT_Error error; FT_Memory memory; FT_Stream stream = NULL; + FT_UInt mode; *astream = NULL; @@ -204,49 +211,56 @@ return FT_THROW( Invalid_Argument ); memory = library->memory; + mode = args->flags & + ( FT_OPEN_MEMORY | FT_OPEN_STREAM | FT_OPEN_PATHNAME ); - if ( FT_NEW( stream ) ) - goto Exit; - - stream->memory = memory; - - if ( args->flags & FT_OPEN_MEMORY ) + if ( mode == FT_OPEN_MEMORY ) { /* create a memory-based stream */ + if ( FT_NEW( stream ) ) + goto Exit; + FT_Stream_OpenMemory( stream, (const FT_Byte*)args->memory_base, (FT_ULong)args->memory_size ); + stream->memory = memory; } #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT - else if ( args->flags & FT_OPEN_PATHNAME ) + else if ( mode == FT_OPEN_PATHNAME ) { /* create a normal system stream */ + if ( FT_NEW( stream ) ) + goto Exit; + + stream->memory = memory; error = FT_Stream_Open( stream, args->pathname ); - stream->pathname.pointer = args->pathname; + if ( error ) + FT_FREE( stream ); } - else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) + else if ( ( mode == FT_OPEN_STREAM ) && args->stream ) { /* use an existing, user-provided stream */ /* in this case, we do not need to allocate a new stream object */ /* since the caller is responsible for closing it himself */ - FT_FREE( stream ); - stream = args->stream; + stream = args->stream; + stream->memory = memory; + error = FT_Err_Ok; } #endif else + { error = FT_THROW( Invalid_Argument ); + if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) + FT_Stream_Close( args->stream ); + } - if ( error ) - FT_FREE( stream ); - else - stream->memory = memory; /* just to be certain */ - - *astream = stream; + if ( !error ) + *astream = stream; Exit: return error; @@ -316,6 +330,19 @@ if ( !error && clazz->init_slot ) error = clazz->init_slot( slot ); +#ifdef FT_CONFIG_OPTION_SVG + /* if SVG table exists, allocate the space in `slot->other` */ + if ( slot->face->face_flags & FT_FACE_FLAG_SVG ) + { + FT_SVG_Document document = NULL; + + + if ( FT_NEW( document ) ) + goto Exit; + slot->other = document; + } +#endif + Exit: return error; } @@ -360,7 +387,18 @@ FT_Pos width, height, pitch; - if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + if ( slot->format == FT_GLYPH_FORMAT_SVG ) + { + FT_Module module; + SVG_Service svg_service; + + + module = FT_Get_Module( slot->library, "ot-svg" ); + svg_service = (SVG_Service)module->clazz->module_interface; + + return (FT_Bool)svg_service->preset_slot( module, slot, FALSE ); + } + else if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) return 1; if ( origin ) @@ -523,7 +561,7 @@ else slot->internal->flags |= FT_GLYPH_OWN_BITMAP; - (void)FT_ALLOC( slot->bitmap.buffer, size ); + FT_MEM_ALLOC( slot->bitmap.buffer, size ); return error; } @@ -535,6 +573,8 @@ ft_glyphslot_free_bitmap( slot ); /* clear all public fields in the glyph slot */ + slot->glyph_index = 0; + FT_ZERO( &slot->metrics ); FT_ZERO( &slot->outline ); @@ -550,11 +590,32 @@ slot->subglyphs = NULL; slot->control_data = NULL; slot->control_len = 0; - slot->other = NULL; - slot->format = FT_GLYPH_FORMAT_NONE; + +#ifndef FT_CONFIG_OPTION_SVG + slot->other = NULL; +#else + if ( !( slot->face->face_flags & FT_FACE_FLAG_SVG ) ) + slot->other = NULL; + else + { + if ( slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG ) + { + FT_Memory memory = slot->face->memory; + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + + + FT_FREE( doc->svg_document ); + slot->internal->load_flags &= ~FT_GLYPH_OWN_GZIP_SVG; + } + } +#endif + + slot->format = FT_GLYPH_FORMAT_NONE; slot->linearHoriAdvance = 0; slot->linearVertAdvance = 0; + slot->advance.x = 0; + slot->advance.y = 0; slot->lsb_delta = 0; slot->rsb_delta = 0; } @@ -567,6 +628,23 @@ FT_Driver_Class clazz = driver->clazz; FT_Memory memory = driver->root.memory; +#ifdef FT_CONFIG_OPTION_SVG + if ( slot->face->face_flags & FT_FACE_FLAG_SVG ) + { + /* free memory in case SVG was there */ + if ( slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG ) + { + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + + + FT_FREE( doc->svg_document ); + + slot->internal->flags &= ~FT_GLYPH_OWN_GZIP_SVG; + } + + FT_FREE( slot->other ); + } +#endif if ( clazz->done_slot ) clazz->done_slot( slot ); @@ -734,6 +812,29 @@ } + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Get_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Face_Internal internal; + + + if ( !face ) + return; + + internal = face->internal; + + if ( matrix ) + *matrix = internal->transform_matrix; + + if ( delta ) + *delta = internal->transform_delta; + } + + static FT_Renderer ft_lookup_glyph_renderer( FT_GlyphSlot slot ); @@ -819,6 +920,11 @@ library = driver->root.library; hinter = library->auto_hinter; + /* undefined scale means no scale */ + if ( face->size->metrics.x_ppem == 0 || + face->size->metrics.y_ppem == 0 ) + load_flags |= FT_LOAD_NO_SCALE; + /* resolve load flags dependencies */ if ( load_flags & FT_LOAD_NO_RECURSE ) @@ -908,11 +1014,21 @@ FT_AutoHinter_Interface hinting; - /* try to load embedded bitmaps first if available */ - /* */ - /* XXX: This is really a temporary hack that should disappear */ - /* promptly with FreeType 2.1! */ - /* */ + /* XXX: The use of the `FT_LOAD_XXX_ONLY` flags is not very */ + /* elegant. */ + + /* try to load SVG documents if available */ + if ( FT_HAS_SVG( face ) ) + { + error = driver->clazz->load_glyph( slot, face->size, + glyph_index, + load_flags | FT_LOAD_SVG_ONLY ); + + if ( !error && slot->format == FT_GLYPH_FORMAT_SVG ) + goto Load_Ok; + } + + /* try to load embedded bitmaps if available */ if ( FT_HAS_FIXED_SIZES( face ) && ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) { @@ -1056,19 +1172,24 @@ #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE5(( "FT_Load_Glyph: index %d, flags 0x%x\n", glyph_index, load_flags )); + FT_TRACE5(( " bitmap %dx%d %s, %s (mode %d)\n", + slot->bitmap.width, + slot->bitmap.rows, + slot->outline.points ? + slot->bitmap.buffer ? "rendered" + : "preset" + : + slot->internal->flags & FT_GLYPH_OWN_BITMAP ? "owned" + : "unowned", + pixel_modes[slot->bitmap.pixel_mode], + slot->bitmap.pixel_mode )); + FT_TRACE5(( "\n" )); FT_TRACE5(( " x advance: %f\n", slot->advance.x / 64.0 )); FT_TRACE5(( " y advance: %f\n", slot->advance.y / 64.0 )); FT_TRACE5(( " linear x advance: %f\n", slot->linearHoriAdvance / 65536.0 )); FT_TRACE5(( " linear y advance: %f\n", slot->linearVertAdvance / 65536.0 )); - FT_TRACE5(( "\n" )); - FT_TRACE5(( " bitmap %dx%d, %s (mode %d)\n", - slot->bitmap.width, - slot->bitmap.rows, - pixel_modes[slot->bitmap.pixel_mode], - slot->bitmap.pixel_mode )); - FT_TRACE5(( "\n" )); { FT_Glyph_Metrics* metrics = &slot->metrics; @@ -1553,7 +1674,6 @@ FT_FREE( stream->base ); stream->size = 0; - stream->base = NULL; stream->close = NULL; } @@ -1782,7 +1902,7 @@ if ( error ) goto Exit; - if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) ) + if ( FT_QALLOC( sfnt_ps, (FT_Long)length ) ) goto Exit; error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length ); @@ -1892,7 +2012,7 @@ goto Exit; } - if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) + if ( FT_QALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) goto Exit; pfb_data[0] = 0x80; @@ -1956,7 +2076,7 @@ { FT_TRACE3(( " Write POST fragment #%d header (4-byte) to buffer" " %p + 0x%08lx\n", - i, pfb_data, pfb_lenpos )); + i, (void*)pfb_data, pfb_lenpos )); if ( pfb_lenpos + 3 > pfb_len + 2 ) goto Exit2; @@ -1971,7 +2091,7 @@ FT_TRACE3(( " Write POST fragment #%d header (6-byte) to buffer" " %p + 0x%08lx\n", - i, pfb_data, pfb_pos )); + i, (void*)pfb_data, pfb_pos )); if ( pfb_pos + 6 > pfb_len + 2 ) goto Exit2; @@ -1994,7 +2114,7 @@ FT_TRACE3(( " Load POST fragment #%d (%ld byte) to buffer" " %p + 0x%08lx\n", - i, rlen, pfb_data, pfb_pos )); + i, rlen, (void*)pfb_data, pfb_pos )); error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen ); if ( error ) @@ -2092,7 +2212,7 @@ if ( error ) goto Exit; - if ( FT_ALLOC( sfnt_data, rlen ) ) + if ( FT_QALLOC( sfnt_data, rlen ) ) return error; error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, (FT_ULong)rlen ); if ( error ) { @@ -2407,6 +2527,16 @@ #endif + /* only use lower 31 bits together with sign bit */ + if ( face_index > 0 ) + face_index &= 0x7FFFFFFFL; + else + { + face_index = -face_index; + face_index &= 0x7FFFFFFFL; + face_index = -face_index; + } + #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE3(( "FT_Open_Face: " )); if ( face_index < 0 ) @@ -2566,7 +2696,7 @@ FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); /* add the face object to its driver's list */ - if ( FT_NEW( node ) ) + if ( FT_QNEW( node ) ) goto Fail; node->data = face; @@ -2681,10 +2811,10 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( !error && face_index < 0 ) { - FT_TRACE3(( "FT_Open_Face: The font has %ld face%s\n" - " and %ld named instance%s for face %ld\n", + FT_TRACE3(( "FT_Open_Face: The font has %ld face%s\n", face->num_faces, - face->num_faces == 1 ? "" : "s", + face->num_faces == 1 ? "" : "s" )); + FT_TRACE3(( " and %ld named instance%s for face %ld\n", face->style_flags >> 16, ( face->style_flags >> 16 ) == 1 ? "" : "s", -face_index - 1 )); @@ -2851,7 +2981,7 @@ memory = face->memory; /* Allocate new size object and perform basic initialisation */ - if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) ) + if ( FT_ALLOC( size, clazz->size_object_size ) || FT_QNEW( node ) ) goto Exit; size->face = face; @@ -3088,10 +3218,12 @@ } - FT_BASE_DEF( void ) + FT_BASE_DEF( FT_Error ) FT_Request_Metrics( FT_Face face, FT_Size_Request req ) { + FT_Error error = FT_Err_Ok; + FT_Size_Metrics* metrics; @@ -3182,8 +3314,18 @@ scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale ); } - metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 ); - metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 ); + scaled_w = ( scaled_w + 32 ) >> 6; + scaled_h = ( scaled_h + 32 ) >> 6; + if ( scaled_w > (FT_Long)FT_USHORT_MAX || + scaled_h > (FT_Long)FT_USHORT_MAX ) + { + FT_ERROR(( "FT_Request_Metrics: Resulting ppem size too large\n" )); + error = FT_ERR( Invalid_Pixel_Size ); + goto Exit; + } + + metrics->x_ppem = (FT_UShort)scaled_w; + metrics->y_ppem = (FT_UShort)scaled_h; ft_recompute_scaled_metrics( face, metrics ); } @@ -3193,6 +3335,9 @@ metrics->x_scale = 1L << 16; metrics->y_scale = 1L << 16; } + + Exit: + return error; } @@ -3256,7 +3401,7 @@ FT_Request_Size( FT_Face face, FT_Size_Request req ) { - FT_Error error = FT_Err_Ok; + FT_Error error; FT_Driver_Class clazz; FT_ULong strike_index; @@ -3264,6 +3409,9 @@ if ( !face ) return FT_THROW( Invalid_Face_Handle ); + if ( !face->size ) + return FT_THROW( Invalid_Size_Handle ); + if ( !req || req->width < 0 || req->height < 0 || req->type >= FT_SIZE_REQUEST_TYPE_MAX ) return FT_THROW( Invalid_Argument ); @@ -3292,13 +3440,15 @@ */ error = FT_Match_Size( face, req, 0, &strike_index ); if ( error ) - return error; + goto Exit; return FT_Select_Size( face, (FT_Int)strike_index ); } else { - FT_Request_Metrics( face, req ); + error = FT_Request_Metrics( face, req ); + if ( error ) + goto Exit; FT_TRACE5(( "FT_Request_Size:\n" )); } @@ -3321,6 +3471,7 @@ } #endif + Exit: return error; } @@ -3645,9 +3796,9 @@ FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1]; - if ( FT_RENEW_ARRAY( face->charmaps, - face->num_charmaps, - face->num_charmaps - 1 ) ) + if ( FT_QRENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps - 1 ) ) return; /* remove it from our list of charmaps */ @@ -3679,7 +3830,7 @@ FT_CharMap charmap, FT_CMap *acmap ) { - FT_Error error = FT_Err_Ok; + FT_Error error; FT_Face face; FT_Memory memory; FT_CMap cmap = NULL; @@ -3704,9 +3855,9 @@ } /* add it to our list of charmaps */ - if ( FT_RENEW_ARRAY( face->charmaps, - face->num_charmaps, - face->num_charmaps + 1 ) ) + if ( FT_QRENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps + 1 ) ) goto Fail; face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; @@ -4400,7 +4551,7 @@ FT_ListNode node = NULL; - if ( FT_NEW( node ) ) + if ( FT_QNEW( node ) ) goto Exit; { @@ -4412,8 +4563,7 @@ render->glyph_format = clazz->glyph_format; /* allocate raster object if needed */ - if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && - clazz->raster_class->raster_new ) + if ( clazz->raster_class && clazz->raster_class->raster_new ) { error = clazz->raster_class->raster_new( memory, &render->raster ); if ( error ) @@ -4423,6 +4573,11 @@ render->render = clazz->render_glyph; } +#ifdef FT_CONFIG_OPTION_SVG + if ( clazz->glyph_format == FT_GLYPH_FORMAT_SVG ) + render->render = clazz->render_glyph; +#endif + /* add to list */ node->data = module; FT_List_Add( &library->renderers, node ); @@ -4460,8 +4615,7 @@ /* release raster object, if any */ - if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && - render->raster ) + if ( render->raster ) render->clazz->raster_class->raster_done( render->raster ); /* remove from list */ @@ -4556,9 +4710,6 @@ switch ( slot->format ) { - case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */ - break; - default: if ( slot->internal->load_flags & FT_LOAD_COLOR ) { @@ -4646,7 +4797,7 @@ else renderer = FT_Lookup_Renderer( library, slot->format, &node ); - error = FT_ERR( Unimplemented_Feature ); + error = FT_ERR( Cannot_Render_Glyph ); while ( renderer ) { error = renderer->render( renderer, slot, render_mode, NULL ); @@ -4662,6 +4813,11 @@ /* format. */ renderer = FT_Lookup_Renderer( library, slot->format, &node ); } + + /* it is not an error if we cannot render a bitmap glyph */ + if ( FT_ERR_EQ( error, Cannot_Render_Glyph ) && + slot->format == FT_GLYPH_FORMAT_BITMAP ) + error = FT_Err_Ok; } } @@ -4734,11 +4890,11 @@ /* we use FT_TRACE7 in this block */ if ( !error && - ft_trace_levels[trace_checksum] >= 7 ) + ft_trace_levels[trace_checksum] >= 7 && + slot->bitmap.buffer ) { if ( slot->bitmap.rows < 128U && - slot->bitmap.width < 128U && - slot->bitmap.buffer ) + slot->bitmap.width < 128U ) { int rows = (int)slot->bitmap.rows; int width = (int)slot->bitmap.width; @@ -5149,16 +5305,16 @@ if ( cur == limit ) { - FT_ERROR(( "%s: can't find module `%s'\n", - func_name, module_name )); + FT_TRACE2(( "%s: can't find module `%s'\n", + func_name, module_name )); return FT_THROW( Missing_Module ); } /* check whether we have a service interface */ if ( !cur[0]->clazz->get_interface ) { - FT_ERROR(( "%s: module `%s' doesn't support properties\n", - func_name, module_name )); + FT_TRACE2(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); return FT_THROW( Unimplemented_Feature ); } @@ -5167,8 +5323,8 @@ FT_SERVICE_ID_PROPERTIES ); if ( !interface ) { - FT_ERROR(( "%s: module `%s' doesn't support properties\n", - func_name, module_name )); + FT_TRACE2(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); return FT_THROW( Unimplemented_Feature ); } @@ -5181,8 +5337,8 @@ if ( missing_func ) { - FT_ERROR(( "%s: property service of module `%s' is broken\n", - func_name, module_name )); + FT_TRACE2(( "%s: property service of module `%s' is broken\n", + func_name, module_name )); return FT_THROW( Unimplemented_Feature ); } @@ -5292,10 +5448,12 @@ if ( !memory || !alibrary ) return FT_THROW( Invalid_Argument ); +#ifndef FT_DEBUG_LOGGING #ifdef FT_DEBUG_LEVEL_ERROR /* init debugging support */ ft_debug_init(); -#endif +#endif /* FT_DEBUG_LEVEL_ERROR */ +#endif /* !FT_DEBUG_LOGGING */ /* first of all, allocate the library object */ if ( FT_NEW( library ) ) @@ -5565,6 +5723,147 @@ else return 0; } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_Paint( FT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colr_layer ) + return sfnt->get_colr_glyph_paint( ttface, + base_glyph, + root_transform, + paint ); + else + return 0; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_ClipBox( FT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !clip_box ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_color_glyph_clipbox ) + return sfnt->get_color_glyph_clipbox( ttface, + base_glyph, + clip_box ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Paint_Layers( FT_Face face, + FT_LayerIterator* layer_iterator, + FT_OpaquePaint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint || !layer_iterator ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_paint_layers ) + return sfnt->get_paint_layers( ttface, layer_iterator, paint ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Paint( FT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_paint ) + return sfnt->get_paint( ttface, opaque_paint, paint ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Colorline_Stops ( FT_Face face, + FT_ColorStop * color_stop, + FT_ColorStopIterator *iterator ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !color_stop || !iterator ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colorline_stops ) + return sfnt->get_colorline_stops ( ttface, color_stop, iterator ); + else + return 0; + } /* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType outline management (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * FreeType API for checking patented TrueType bytecode instructions * (body). Obsolete, retained for backward compatibility. * - * Copyright (C) 2007-2020 by + * Copyright (C) 2007-2022 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Get and set properties of PostScript drivers (body). * See `ftdriver.h' for available properties. * - * Copyright (C) 2017-2020 by + * Copyright (C) 2017-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -220,7 +220,7 @@ return error; } - FT_TRACE0(( "ps_property_set: missing property `%s'\n", + FT_TRACE2(( "ps_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -275,7 +275,7 @@ return error; } - FT_TRACE0(( "ps_property_get: missing property `%s'\n", + FT_TRACE2(( "ps_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (body). * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * Masatake YAMATO and Redhat K.K. * * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are @@ -167,16 +167,11 @@ } - static int - ft_raccess_sort_ref_by_id( FT_RFork_Ref* a, - FT_RFork_Ref* b ) - { - if ( a->res_id < b->res_id ) - return -1; - else if ( a->res_id > b->res_id ) - return 1; - else - return 0; + FT_COMPARE_DEF( int ) + ft_raccess_sort_ref_by_id( const void* a, + const void* b ) + { + return ( (FT_RFork_Ref*)a )->res_id - ( (FT_RFork_Ref*)b )->res_id; } @@ -256,7 +251,7 @@ if ( error ) return error; - if ( FT_NEW_ARRAY( ref, *count ) ) + if ( FT_QNEW_ARRAY( ref, *count ) ) return error; for ( j = 0; j < *count; j++ ) @@ -294,8 +289,7 @@ ft_qsort( ref, (size_t)*count, sizeof ( FT_RFork_Ref ), - ( int(*)(const void*, - const void*) )ft_raccess_sort_ref_by_id ); + ft_raccess_sort_ref_by_id ); FT_TRACE3(( " -- sort resources by their ids --\n" )); @@ -305,7 +299,7 @@ j, ref[j].res_id, ref[j].offset )); } - if ( FT_NEW_ARRAY( offsets_internal, *count ) ) + if ( FT_QNEW_ARRAY( offsets_internal, *count ) ) goto Exit; /* XXX: duplicated reference ID, @@ -608,7 +602,7 @@ if ( base_file_len + 6 > FT_INT_MAX ) return FT_THROW( Array_Too_Large ); - if ( FT_ALLOC( newpath, base_file_len + 6 ) ) + if ( FT_QALLOC( newpath, base_file_len + 6 ) ) return error; FT_MEM_COPY( newpath, base_file_name, base_file_len ); @@ -644,7 +638,7 @@ if ( base_file_len + 18 > FT_INT_MAX ) return FT_THROW( Array_Too_Large ); - if ( FT_ALLOC( newpath, base_file_len + 18 ) ) + if ( FT_QALLOC( newpath, base_file_len + 18 ) ) return error; FT_MEM_COPY( newpath, base_file_name, base_file_len ); @@ -874,13 +868,11 @@ const char* tmp; const char* slash; size_t new_length; - FT_Error error = FT_Err_Ok; - - FT_UNUSED( error ); + FT_Error error; new_length = ft_strlen( original_name ) + ft_strlen( insertion ); - if ( FT_ALLOC( new_name, new_length + 1 ) ) + if ( FT_QALLOC( new_name, new_length + 1 ) ) return NULL; tmp = ft_strrchr( original_name, '/' ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c 2022-07-14 08:05:38.000000000 +0000 @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -65,7 +65,7 @@ FT_Stream stream = face->stream; - if ( FT_NEW_ARRAY ( entry->string, entry->stringLength ) || + if ( FT_QNEW_ARRAY ( entry->string, entry->stringLength ) || FT_STREAM_SEEK( entry->stringOffset ) || FT_STREAM_READ( entry->string, entry->stringLength ) ) { @@ -121,7 +121,7 @@ FT_Stream stream = face->stream; - if ( FT_NEW_ARRAY ( entry->string, entry->stringLength ) || + if ( FT_QNEW_ARRAY ( entry->string, entry->stringLength ) || FT_STREAM_SEEK( entry->stringOffset ) || FT_STREAM_READ( entry->string, entry->stringLength ) ) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftstream.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftstream.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftstream.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftstream.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * I/O stream support (body). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -61,7 +61,7 @@ if ( stream->read ) { - if ( stream->read( stream, pos, 0, 0 ) ) + if ( stream->read( stream, pos, NULL, 0 ) ) { FT_ERROR(( "FT_Stream_Seek:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", @@ -347,17 +347,17 @@ } - FT_BASE_DEF( FT_Char ) - FT_Stream_GetChar( FT_Stream stream ) + FT_BASE_DEF( FT_Byte ) + FT_Stream_GetByte( FT_Stream stream ) { - FT_Char result; + FT_Byte result; FT_ASSERT( stream && stream->cursor ); result = 0; if ( stream->cursor < stream->limit ) - result = (FT_Char)*stream->cursor++; + result = *stream->cursor++; return result; } @@ -455,8 +455,8 @@ } - FT_BASE_DEF( FT_Char ) - FT_Stream_ReadChar( FT_Stream stream, + FT_BASE_DEF( FT_Byte ) + FT_Stream_ReadByte( FT_Stream stream, FT_Error* error ) { FT_Byte result = 0; @@ -464,31 +464,32 @@ FT_ASSERT( stream ); - *error = FT_Err_Ok; - - if ( stream->read ) + if ( stream->pos < stream->size ) { - if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) - goto Fail; - } - else - { - if ( stream->pos < stream->size ) - result = stream->base[stream->pos]; + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) + goto Fail; + } else - goto Fail; + result = stream->base[stream->pos]; } + else + goto Fail; + stream->pos++; - return (FT_Char)result; + *error = FT_Err_Ok; + + return result; Fail: *error = FT_THROW( Invalid_Stream_Operation ); - FT_ERROR(( "FT_Stream_ReadChar:" + FT_ERROR(( "FT_Stream_ReadByte:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } @@ -497,14 +498,12 @@ FT_Error* error ) { FT_Byte reads[2]; - FT_Byte* p = 0; + FT_Byte* p; FT_UShort result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 1 < stream->size ) { if ( stream->read ) @@ -525,6 +524,8 @@ stream->pos += 2; + *error = FT_Err_Ok; + return result; Fail: @@ -533,7 +534,7 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } @@ -542,14 +543,12 @@ FT_Error* error ) { FT_Byte reads[2]; - FT_Byte* p = 0; + FT_Byte* p; FT_UShort result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 1 < stream->size ) { if ( stream->read ) @@ -570,6 +569,8 @@ stream->pos += 2; + *error = FT_Err_Ok; + return result; Fail: @@ -578,7 +579,7 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } @@ -587,14 +588,12 @@ FT_Error* error ) { FT_Byte reads[3]; - FT_Byte* p = 0; + FT_Byte* p; FT_ULong result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 2 < stream->size ) { if ( stream->read ) @@ -615,6 +614,8 @@ stream->pos += 3; + *error = FT_Err_Ok; + return result; Fail: @@ -623,7 +624,7 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } @@ -632,14 +633,12 @@ FT_Error* error ) { FT_Byte reads[4]; - FT_Byte* p = 0; + FT_Byte* p; FT_ULong result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 3 < stream->size ) { if ( stream->read ) @@ -660,6 +659,8 @@ stream->pos += 4; + *error = FT_Err_Ok; + return result; Fail: @@ -668,7 +669,7 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } @@ -677,14 +678,12 @@ FT_Error* error ) { FT_Byte reads[4]; - FT_Byte* p = 0; + FT_Byte* p; FT_ULong result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 3 < stream->size ) { if ( stream->read ) @@ -705,6 +704,8 @@ stream->pos += 4; + *error = FT_Err_Ok; + return result; Fail: @@ -713,7 +714,7 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType path stroker (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -974,7 +974,8 @@ FT_StrokeBorder border = stroker->borders + side; FT_Angle phi, theta, rotate; FT_Fixed length; - FT_Vector sigma, delta; + FT_Vector sigma = { 0, 0 }; + FT_Vector delta; FT_Error error = FT_Err_Ok; FT_Bool intersect; /* use intersection of lines? */ @@ -1048,7 +1049,7 @@ { /* this is a mitered (pointed) or beveled (truncated) corner */ FT_Fixed radius = stroker->radius; - FT_Vector sigma; + FT_Vector sigma = { 0, 0 }; FT_Angle theta = 0, phi = 0; FT_Bool bevel, fixed_bevel; @@ -1528,7 +1529,8 @@ stroker->angle_in = angle_out; } - stroker->center = *to; + stroker->center = *to; + stroker->line_length = 0; Exit: return error; @@ -1744,7 +1746,8 @@ stroker->angle_in = angle_out; } - stroker->center = *to; + stroker->center = *to; + stroker->line_length = 0; Exit: return error; @@ -1897,13 +1900,9 @@ } else { - FT_Angle turn; - FT_Int inside_side; - - /* close the path if needed */ - if ( stroker->center.x != stroker->subpath_start.x || - stroker->center.y != stroker->subpath_start.y ) + if ( !FT_IS_SMALL( stroker->center.x - stroker->subpath_start.x ) || + !FT_IS_SMALL( stroker->center.y - stroker->subpath_start.y ) ) { error = FT_Stroker_LineTo( stroker, &stroker->subpath_start ); if ( error ) @@ -1912,29 +1911,11 @@ /* process the corner */ stroker->angle_out = stroker->subpath_angle; - turn = FT_Angle_Diff( stroker->angle_in, - stroker->angle_out ); - - /* no specific corner processing is required if the turn is 0 */ - if ( turn != 0 ) - { - /* when we turn to the right, the inside side is 0 */ - /* otherwise, the inside side is 1 */ - inside_side = ( turn < 0 ); - - error = ft_stroker_inside( stroker, - inside_side, - stroker->subpath_line_length ); - if ( error ) - goto Exit; - /* process the outside side */ - error = ft_stroker_outside( stroker, - !inside_side, - stroker->subpath_line_length ); - if ( error ) - goto Exit; - } + error = ft_stroker_process_corner( stroker, + stroker->subpath_line_length ); + if ( error ) + goto Exit; /* then end our two subpaths */ ft_stroke_border_close( stroker->borders + 0, FALSE ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType synthesizing code for emboldening and slanting (body). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * ANSI-specific FreeType low-level system interface (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -275,7 +275,7 @@ stream->close = ft_ansi_stream_close; FT_TRACE1(( "FT_Stream_Open:" )); - FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", + FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", filepathname, stream->size )); return FT_Err_Ok; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (body). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -53,7 +53,7 @@ }; -#ifdef FT_LONG64 +#ifdef FT_INT64 /* multiply a given value by the CORDIC shrink factor */ static FT_Fixed @@ -76,7 +76,7 @@ return s < 0 ? -val : val; } -#else /* !FT_LONG64 */ +#else /* !FT_INT64 */ /* multiply a given value by the CORDIC shrink factor */ static FT_Fixed @@ -125,7 +125,7 @@ return s < 0 ? -val : val; } -#endif /* !FT_LONG64 */ +#endif /* !FT_INT64 */ /* undefined and never called for zero vector */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/fttype1.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/fttype1.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/fttype1.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/fttype1.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType utility file for PS names support (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftutil.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftutil.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/base/ftutil.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/base/ftutil.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType utility file for memory and list management (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * OpenType font driver implementation (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -345,8 +345,8 @@ else { FT_ERROR(( "cff_get_glyph_name:" - " cannot get glyph name from a CFF2 font\n" - " " + " cannot get glyph name from a CFF2 font\n" )); + FT_ERROR(( " " " without the `psnames' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; @@ -356,8 +356,8 @@ if ( !font->psnames ) { FT_ERROR(( "cff_get_glyph_name:" - " cannot get glyph name from CFF & CEF fonts\n" - " " + " cannot get glyph name from CFF & CEF fonts\n" )); + FT_ERROR(( " " " without the `psnames' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; @@ -412,8 +412,8 @@ else { FT_ERROR(( "cff_get_name_index:" - " cannot get glyph index from a CFF2 font\n" - " " + " cannot get glyph index from a CFF2 font\n" )); + FT_ERROR(( " " " without the `psnames' module\n" )); return 0; } @@ -474,11 +474,11 @@ if ( cff && !cff->font_info ) { CFF_FontRecDict dict = &cff->top_font.font_dict; - PS_FontInfoRec *font_info = NULL; FT_Memory memory = face->root.memory; + PS_FontInfoRec* font_info = NULL; - if ( FT_ALLOC( font_info, sizeof ( *font_info ) ) ) + if ( FT_QNEW( font_info ) ) goto Fail; font_info->version = cff_index_get_sid_string( cff, @@ -515,15 +515,15 @@ FT_Error error = FT_Err_Ok; - if ( cff && cff->font_extra == NULL ) + if ( cff && !cff->font_extra ) { CFF_FontRecDict dict = &cff->top_font.font_dict; - PS_FontExtraRec* font_extra = NULL; FT_Memory memory = face->root.memory; + PS_FontExtraRec* font_extra = NULL; FT_String* embedded_postscript; - if ( FT_ALLOC( font_extra, sizeof ( *font_extra ) ) ) + if ( FT_QNEW( font_extra ) ) goto Fail; font_extra->fs_type = 0U; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level OpenType driver interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CFF error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -29,6 +29,14 @@ #include "cfferrs.h" +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#define IS_DEFAULT_INSTANCE( _face ) \ + ( !( FT_IS_NAMED_INSTANCE( _face ) || \ + FT_IS_VARIATION( _face ) ) ) +#else +#define IS_DEFAULT_INSTANCE( _face ) 1 +#endif + /************************************************************************** * @@ -59,7 +67,7 @@ *pointer = (FT_Byte*)data.pointer; - *length = (FT_ULong)data.length; + *length = data.length; return error; } @@ -94,7 +102,7 @@ data.pointer = *pointer; - data.length = (FT_Int)length; + data.length = (FT_UInt)length; face->root.internal->incremental_interface->funcs->free_glyph_data( face->root.internal->incremental_interface->object, &data ); @@ -255,8 +263,8 @@ if ( size->strike_index != 0xFFFFFFFFUL && - sfnt->load_eblc && - ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && + IS_DEFAULT_INSTANCE( size->root.face ) ) { TT_SBit_MetricsRec metrics; @@ -346,6 +354,76 @@ if ( load_flags & FT_LOAD_SBITS_ONLY ) return FT_THROW( Invalid_Argument ); +#ifdef FT_CONFIG_OPTION_SVG + /* check for OT-SVG */ + if ( ( load_flags & FT_LOAD_COLOR ) && + ( (TT_Face)glyph->root.face )->svg ) + { + /* + * We load the SVG document and try to grab the advances from the + * table. For the bearings we rely on the presetting hook to do that. + */ + + FT_Short dummy; + FT_UShort advanceX; + FT_UShort advanceY; + SFNT_Service sfnt; + + + if ( size->root.metrics.x_ppem < 1 || + size->root.metrics.y_ppem < 1 ) + { + error = FT_THROW( Invalid_Size_Handle ); + return error; + } + + FT_TRACE3(( "Trying to load SVG glyph\n" )); + + sfnt = (SFNT_Service)((TT_Face)glyph->root.face)->sfnt; + error = sfnt->load_svg_doc( (FT_GlyphSlot)glyph, glyph_index ); + if ( !error ) + { + FT_TRACE3(( "Successfully loaded SVG glyph\n" )); + + glyph->root.format = FT_GLYPH_FORMAT_SVG; + + /* + * If horizontal or vertical advances are not present in the table, + * this is a problem with the font since the standard requires them. + * However, we are graceful and calculate the values by ourselves + * for the vertical case. + */ + sfnt->get_metrics( face, + FALSE, + glyph_index, + &dummy, + &advanceX ); + sfnt->get_metrics( face, + TRUE, + glyph_index, + &dummy, + &advanceY ); + + advanceX = + (FT_UShort)FT_MulDiv( advanceX, + glyph->root.face->size->metrics.x_ppem, + glyph->root.face->units_per_EM ); + advanceY = + (FT_UShort)FT_MulDiv( advanceY, + glyph->root.face->size->metrics.y_ppem, + glyph->root.face->units_per_EM ); + + glyph->root.metrics.horiAdvance = advanceX << 6; + glyph->root.metrics.vertAdvance = advanceY << 6; + + return error; + } + + FT_TRACE3(( "Failed to load SVG glyph\n" )); + } + +#endif /* FT_CONFIG_OPTION_SVG */ + /* if we have a CID subfont, use its matrix (which has already */ /* been multiplied with the root matrix) */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffload.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffload.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffload.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffload.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * OpenType and CFF data/program tables loader (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -356,9 +356,9 @@ data_size = (FT_ULong)( idx->count + 1 ) * offsize; - if ( FT_NEW_ARRAY( idx->offsets, idx->count + 1 ) || - FT_STREAM_SEEK( idx->start + idx->hdr_size ) || - FT_FRAME_ENTER( data_size ) ) + if ( FT_QNEW_ARRAY( idx->offsets, idx->count + 1 ) || + FT_STREAM_SEEK( idx->start + idx->hdr_size ) || + FT_FRAME_ENTER( data_size ) ) goto Exit; poff = idx->offsets; @@ -400,7 +400,7 @@ /* Allocate a table containing pointers to an index's elements. */ /* The `pool' argument makes this function convert the index */ - /* entries to C-style strings (this is, NULL-terminated). */ + /* entries to C-style strings (this is, null-terminated). */ static FT_Error cff_index_get_pointers( CFF_Index idx, FT_Byte*** table, @@ -427,7 +427,7 @@ new_size = idx->data_size + idx->count; if ( idx->count > 0 && - !FT_NEW_ARRAY( tbl, idx->count + 1 ) && + !FT_QNEW_ARRAY( tbl, idx->count + 1 ) && ( !pool || !FT_ALLOC( new_bytes, new_size ) ) ) { FT_ULong n, cur_offset; @@ -622,7 +622,7 @@ FT_Byte* bytes; FT_ULong byte_len; FT_Error error; - FT_String* name = 0; + FT_String* name = NULL; if ( !idx->stream ) /* CFF2 does not include a name index */ @@ -634,10 +634,9 @@ if ( error ) goto Exit; - if ( !FT_ALLOC( name, byte_len + 1 ) ) + if ( !FT_QALLOC( name, byte_len + 1 ) ) { - if ( byte_len ) - FT_MEM_COPY( name, bytes, byte_len ); + FT_MEM_COPY( name, bytes, byte_len ); name[byte_len] = 0; } cff_index_forget_element( idx, &bytes ); @@ -772,8 +771,7 @@ case 3: /* first, compare to the cache */ - if ( (FT_UInt)( glyph_index - fdselect->cache_first ) < - fdselect->cache_count ) + if ( glyph_index - fdselect->cache_first < fdselect->cache_count ) { fd = fdselect->cache_fd; break; @@ -836,7 +834,6 @@ { FT_Error error = FT_Err_Ok; FT_UInt i; - FT_Long j; FT_UShort max_cid = 0; @@ -854,9 +851,10 @@ /* When multiple GIDs map to the same CID, we choose the lowest */ /* GID. This is not described in any spec, but it matches the */ - /* behaviour of recent Acroread versions. */ - for ( j = (FT_Long)num_glyphs - 1; j >= 0; j-- ) - charset->cids[charset->sids[j]] = (FT_UShort)j; + /* behaviour of recent Acroread versions. The loop stops when */ + /* the unsigned index wraps around after reaching zero. */ + for ( i = num_glyphs - 1; i < num_glyphs; i-- ) + charset->cids[charset->sids[i]] = (FT_UShort)i; charset->max_cid = max_cid; charset->num_glyphs = num_glyphs; @@ -932,7 +930,7 @@ goto Exit; /* Allocate memory for sids. */ - if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* assign the .notdef glyph */ @@ -1018,14 +1016,14 @@ case 0: if ( num_glyphs > 229 ) { - FT_ERROR(( "cff_charset_load: implicit charset larger than\n" - "predefined charset (Adobe ISO-Latin)\n" )); + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe ISO-Latin)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ - if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ @@ -1036,14 +1034,14 @@ case 1: if ( num_glyphs > 166 ) { - FT_ERROR(( "cff_charset_load: implicit charset larger than\n" - "predefined charset (Adobe Expert)\n" )); + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe Expert)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ - if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ @@ -1054,14 +1052,14 @@ case 2: if ( num_glyphs > 87 ) { - FT_ERROR(( "cff_charset_load: implicit charset larger than\n" - "predefined charset (Adobe Expert Subset)\n" )); + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe Expert Subset)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ - if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ @@ -1087,7 +1085,6 @@ FT_FREE( charset->cids ); charset->format = 0; charset->offset = 0; - charset->sids = 0; } return error; @@ -1141,6 +1138,8 @@ { FT_UInt vsOffset; FT_UInt format; + FT_UInt dataCount; + FT_UInt regionCount; FT_ULong regionListOffset; @@ -1163,16 +1162,16 @@ } /* read top level fields */ - if ( FT_READ_ULONG( regionListOffset ) || - FT_READ_USHORT( vstore->dataCount ) ) + if ( FT_READ_ULONG( regionListOffset ) || + FT_READ_USHORT( dataCount ) ) goto Exit; /* make temporary copy of item variation data offsets; */ /* we'll parse region list first, then come back */ - if ( FT_NEW_ARRAY( dataOffsetArray, vstore->dataCount ) ) + if ( FT_QNEW_ARRAY( dataOffsetArray, dataCount ) ) goto Exit; - for ( i = 0; i < vstore->dataCount; i++ ) + for ( i = 0; i < dataCount; i++ ) { if ( FT_READ_ULONG( dataOffsetArray[i] ) ) goto Exit; @@ -1181,20 +1180,24 @@ /* parse regionList and axisLists */ if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) || FT_READ_USHORT( vstore->axisCount ) || - FT_READ_USHORT( vstore->regionCount ) ) + FT_READ_USHORT( regionCount ) ) goto Exit; - if ( FT_NEW_ARRAY( vstore->varRegionList, vstore->regionCount ) ) + vstore->regionCount = 0; + if ( FT_QNEW_ARRAY( vstore->varRegionList, regionCount ) ) goto Exit; - for ( i = 0; i < vstore->regionCount; i++ ) + for ( i = 0; i < regionCount; i++ ) { CFF_VarRegion* region = &vstore->varRegionList[i]; - if ( FT_NEW_ARRAY( region->axisList, vstore->axisCount ) ) + if ( FT_QNEW_ARRAY( region->axisList, vstore->axisCount ) ) goto Exit; + /* keep track of how many axisList to deallocate on error */ + vstore->regionCount++; + for ( j = 0; j < vstore->axisCount; j++ ) { CFF_AxisCoords* axis = ®ion->axisList[j]; @@ -1214,10 +1217,11 @@ } /* use dataOffsetArray now to parse varData items */ - if ( FT_NEW_ARRAY( vstore->varData, vstore->dataCount ) ) + vstore->dataCount = 0; + if ( FT_QNEW_ARRAY( vstore->varData, dataCount ) ) goto Exit; - for ( i = 0; i < vstore->dataCount; i++ ) + for ( i = 0; i < dataCount; i++ ) { CFF_VarData* data = &vstore->varData[i]; @@ -1236,9 +1240,12 @@ if ( FT_READ_USHORT( data->regionIdxCount ) ) goto Exit; - if ( FT_NEW_ARRAY( data->regionIndices, data->regionIdxCount ) ) + if ( FT_QNEW_ARRAY( data->regionIndices, data->regionIdxCount ) ) goto Exit; + /* keep track of how many regionIndices to deallocate on error */ + vstore->dataCount++; + for ( j = 0; j < data->regionIdxCount; j++ ) { if ( FT_READ_USHORT( data->regionIndices[j] ) ) @@ -1322,9 +1329,9 @@ /* increase or allocate `blend_stack' and reset `blend_top'; */ /* prepare to append `numBlends' values to the buffer */ - if ( FT_REALLOC( subFont->blend_stack, - subFont->blend_alloc, - subFont->blend_alloc + size ) ) + if ( FT_QREALLOC( subFont->blend_stack, + subFont->blend_alloc, + subFont->blend_alloc + size ) ) goto Exit; subFont->blend_top = subFont->blend_stack + subFont->blend_used; @@ -1437,9 +1444,7 @@ /* prepare buffer for the blend vector */ len = varData->regionIdxCount + 1; /* add 1 for default component */ - if ( FT_REALLOC( blend->BV, - blend->lenBV * sizeof( *blend->BV ), - len * sizeof( *blend->BV ) ) ) + if ( FT_QRENEW_ARRAY( blend->BV, blend->lenBV, len ) ) goto Exit; blend->lenBV = len; @@ -1456,10 +1461,8 @@ if ( master == 0 ) { blend->BV[master] = FT_FIXED_ONE; - FT_TRACE4(( " build blend vector len %d\n" - " [ %f ", - len, - blend->BV[master] / 65536.0 )); + FT_TRACE4(( " build blend vector len %d\n", len )); + FT_TRACE4(( " [ %f ", blend->BV[master] / 65536.0 )); continue; } @@ -1543,9 +1546,7 @@ if ( lenNDV != 0 ) { /* user has set a normalized vector */ - if ( FT_REALLOC( blend->lastNDV, - blend->lenNDV * sizeof ( *NDV ), - lenNDV * sizeof ( *NDV ) ) ) + if ( FT_QRENEW_ARRAY( blend->lastNDV, blend->lenNDV, lenNDV ) ) goto Exit; FT_MEM_COPY( blend->lastNDV, @@ -1827,7 +1828,8 @@ /* Construct code to GID mapping from code to SID mapping */ /* and charset. */ - encoding->count = 0; + encoding->offset = offset; /* used in cff_face_init */ + encoding->count = 0; error = cff_charset_compute_cids( charset, num_glyphs, stream->memory ); @@ -2363,8 +2365,8 @@ if ( font->name_index.count > 1 ) { FT_ERROR(( "cff_font_load:" - " invalid CFF font with multiple subfonts\n" - " " + " invalid CFF font with multiple subfonts\n" )); + FT_ERROR(( " " " in SFNT wrapper\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffload.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffload.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffload.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffload.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * OpenType & CFF data/program tables loader (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * OpenType objects manager (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -283,6 +283,8 @@ cff_size_request( FT_Size size, FT_Size_Request req ) { + FT_Error error; + CFF_Size cffsize = (CFF_Size)size; PSH_Globals_Funcs funcs; @@ -304,7 +306,9 @@ #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ - FT_Request_Metrics( size->face, req ); + error = FT_Request_Metrics( size->face, req ); + if ( error ) + goto Exit; funcs = cff_size_get_globals_funcs( cffsize ); @@ -345,7 +349,8 @@ } } - return FT_Err_Ok; + Exit: + return error; } @@ -406,9 +411,7 @@ FT_String* result; - (void)FT_STRDUP( result, source ); - - FT_UNUSED( error ); + FT_MEM_STRDUP( result, source ); return result; } @@ -659,8 +662,8 @@ if ( dict->cid_registry == 0xFFFFU && !psnames ) { FT_ERROR(( "cff_face_init:" - " cannot open CFF & CEF fonts\n" - " " + " cannot open CFF & CEF fonts\n" )); + FT_ERROR(( " " " without the `psnames' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; @@ -684,13 +687,13 @@ /* In Multiple Master CFFs, two SIDs hold the Normalize Design */ /* Vector (NDV) and Convert Design Vector (CDV) charstrings, */ - /* which may contain NULL bytes in the middle of the data, too. */ + /* which may contain null bytes in the middle of the data, too. */ /* We thus access `cff->strings' directly. */ for ( idx = 1; idx < cff->num_strings; idx++ ) { FT_Byte* s1 = cff->strings[idx - 1]; FT_Byte* s2 = cff->strings[idx]; - FT_PtrDist s1len = s2 - s1 - 1; /* without the final NULL byte */ + FT_PtrDist s1len = s2 - s1 - 1; /* without the final null byte */ FT_PtrDist l; @@ -1049,11 +1052,11 @@ { FT_CharMapRec cmaprec; FT_CharMap cmap; - FT_UInt nn; + FT_Int nn; CFF_Encoding encoding = &cff->encoding; - for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ ) + for ( nn = 0; nn < cffface->num_charmaps; nn++ ) { cmap = cffface->charmaps[nn]; @@ -1078,7 +1081,7 @@ cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; cmaprec.encoding = FT_ENCODING_UNICODE; - nn = (FT_UInt)cffface->num_charmaps; + nn = cffface->num_charmaps; error = FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL ); @@ -1089,7 +1092,7 @@ error = FT_Err_Ok; /* if no Unicode charmap was previously selected, select this one */ - if ( !cffface->charmap && nn != (FT_UInt)cffface->num_charmaps ) + if ( !cffface->charmap && nn != cffface->num_charmaps ) cffface->charmap = cffface->charmaps[nn]; Skip_Unicode: @@ -1174,11 +1177,7 @@ /* set default property values, cf. `ftcffdrv.h' */ -#ifdef CFF_CONFIG_OPTION_OLD_ENGINE - driver->hinting_engine = FT_HINTING_FREETYPE; -#else driver->hinting_engine = FT_HINTING_ADOBE; -#endif driver->no_stem_darkening = TRUE; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * OpenType objects manager (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CFF token stream parser (body) * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -62,7 +62,7 @@ parser->num_axes = num_axes; /* allocate the stack buffer */ - if ( FT_NEW_ARRAY( parser->stack, stackSize ) ) + if ( FT_QNEW_ARRAY( parser->stack, stackSize ) ) { FT_FREE( parser->stack ); goto Exit; @@ -713,9 +713,10 @@ ( max_scaling - min_scaling ) > 9 ) { FT_TRACE1(( "cff_parse_font_matrix:" - " strange scaling values (minimum %ld, maximum %ld),\n" - " " - " using default matrix\n", min_scaling, max_scaling )); + " strange scaling values (minimum %ld, maximum %ld),\n", + min_scaling, max_scaling )); + FT_TRACE1(( " " + " using default matrix\n" )); goto Unlikely; } @@ -1515,6 +1516,7 @@ case cff_kind_fixed_thousand: FT_TRACE4(( " %f\n", (double)val / 65536 / 1000 )); + break; default: ; /* never reached */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CFF token stream parser (specification) * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CFF token definitions (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID-keyed Type1 Glyph Loader (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -63,7 +63,7 @@ #endif - FT_TRACE1(( "cid_load_glyph: glyph index %d\n", glyph_index )); + FT_TRACE1(( "cid_load_glyph: glyph index %u\n", glyph_index )); #ifdef FT_CONFIG_OPTION_INCREMENTAL @@ -76,20 +76,17 @@ error = inc->funcs->get_glyph_data( inc->object, glyph_index, &glyph_data ); - if ( error ) + if ( error || glyph_data.length < cid->fd_bytes ) goto Exit; p = (FT_Byte*)glyph_data.pointer; - fd_select = cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); + fd_select = cid_get_offset( &p, cid->fd_bytes ); - if ( glyph_data.length != 0 ) - { - glyph_length = (FT_ULong)( glyph_data.length - cid->fd_bytes ); - (void)FT_ALLOC( charstring, glyph_length ); - if ( !error ) - ft_memcpy( charstring, glyph_data.pointer + cid->fd_bytes, + glyph_length = glyph_data.length - cid->fd_bytes; + + if ( !FT_QALLOC( charstring, glyph_length ) ) + FT_MEM_COPY( charstring, glyph_data.pointer + cid->fd_bytes, glyph_length ); - } inc->funcs->free_glyph_data( inc->object, &glyph_data ); @@ -104,7 +101,7 @@ /* For ordinary fonts read the CID font dictionary index */ /* and charstring offset from the CIDMap. */ { - FT_UInt entry_len = (FT_UInt)( cid->fd_bytes + cid->gd_bytes ); + FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes; FT_ULong off1, off2; @@ -114,15 +111,15 @@ goto Exit; p = (FT_Byte*)stream->cursor; - fd_select = cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); - off1 = cid_get_offset( &p, (FT_Byte)cid->gd_bytes ); + fd_select = cid_get_offset( &p, cid->fd_bytes ); + off1 = cid_get_offset( &p, cid->gd_bytes ); p += cid->fd_bytes; - off2 = cid_get_offset( &p, (FT_Byte)cid->gd_bytes ); + off2 = cid_get_offset( &p, cid->gd_bytes ); FT_FRAME_EXIT(); - if ( fd_select >= (FT_ULong)cid->num_dicts || - off2 > stream->size || - off1 > off2 ) + if ( fd_select >= cid->num_dicts || + off2 > stream->size || + off1 > off2 ) { FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" )); error = FT_THROW( Invalid_Offset ); @@ -130,11 +127,10 @@ } glyph_length = off2 - off1; - if ( glyph_length == 0 ) - goto Exit; - if ( FT_ALLOC( charstring, glyph_length ) ) - goto Exit; - if ( FT_STREAM_READ_AT( cid->data_offset + off1, + + if ( glyph_length == 0 || + FT_QALLOC( charstring, glyph_length ) || + FT_STREAM_READ_AT( cid->data_offset + off1, charstring, glyph_length ) ) goto Exit; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidload.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidload.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidload.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidload.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -41,7 +41,7 @@ /* read a single offset */ FT_LOCAL_DEF( FT_ULong ) cid_get_offset( FT_Byte* *start, - FT_Byte offsize ) + FT_UInt offsize ) { FT_ULong result; FT_Byte* p = *start; @@ -113,7 +113,7 @@ CID_FaceDict dict; - if ( parser->num_dict < 0 || parser->num_dict >= cid->num_dicts ) + if ( parser->num_dict >= cid->num_dicts ) { FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n", keyword->ident )); @@ -164,7 +164,7 @@ FT_Fixed temp_scale; - if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) + if ( parser->num_dict < face->cid.num_dicts ) { FT_Matrix* matrix; FT_Vector* offset; @@ -244,11 +244,11 @@ FT_Memory memory = face->root.memory; FT_Stream stream = parser->stream; FT_Error error = FT_Err_Ok; - FT_Long num_dicts; + FT_Long num_dicts, max_dicts; num_dicts = cid_parser_to_int( parser ); - if ( num_dicts < 0 ) + if ( num_dicts < 0 || num_dicts > FT_INT_MAX ) { FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" )); goto Exit; @@ -272,18 +272,18 @@ * need a `dup X' at the very beginning and a `put' at the end, so a * rough guess using 100 bytes as the minimum is justified. */ - if ( (FT_ULong)num_dicts > stream->size / 100 ) + max_dicts = (FT_Long)( stream->size / 100 ); + if ( num_dicts > max_dicts ) { FT_TRACE0(( "parse_fd_array: adjusting FDArray size" " (from %ld to %ld)\n", - num_dicts, - stream->size / 100 )); - num_dicts = (FT_Long)( stream->size / 100 ); + num_dicts, max_dicts )); + num_dicts = max_dicts; } if ( !cid->font_dicts ) { - FT_Int n; + FT_UInt n; if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) @@ -322,7 +322,7 @@ CID_FaceDict dict; - if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) + if ( parser->num_dict < face->cid.num_dicts ) { dict = face->cid.font_dicts + parser->num_dict; @@ -345,7 +345,7 @@ CID_Parser* parser ) { #ifdef FT_DEBUG_LEVEL_TRACE - if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) + if ( parser->num_dict < face->cid.num_dicts ) { T1_TokenRec token; FT_UInt len; @@ -427,7 +427,7 @@ parser->num_dict++; #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE4(( " FontDict %d", parser->num_dict )); + FT_TRACE4(( " FontDict %u", parser->num_dict )); if ( parser->num_dict > face->cid.num_dicts ) FT_TRACE4(( " (ignored)" )); FT_TRACE4(( "\n" )); @@ -517,7 +517,7 @@ FT_Memory memory = face->root.memory; FT_Stream stream = face->cid_stream; FT_Error error; - FT_Int n; + FT_UInt n; CID_Subrs subr; FT_UInt max_offsets = 0; FT_ULong* offsets = NULL; @@ -552,20 +552,20 @@ goto Fail; } - if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) ) + if ( FT_QRENEW_ARRAY( offsets, max_offsets, new_max ) ) goto Fail; max_offsets = new_max; } /* read the subrmap's offsets */ - if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || - FT_FRAME_ENTER( ( num_subrs + 1 ) * (FT_UInt)dict->sd_bytes ) ) + if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || + FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) ) goto Fail; p = (FT_Byte*)stream->cursor; for ( count = 0; count <= num_subrs; count++ ) - offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes ); + offsets[count] = cid_get_offset( &p, dict->sd_bytes ); FT_FRAME_EXIT(); @@ -589,12 +589,12 @@ /* allocate, and read them */ data_len = offsets[num_subrs] - offsets[0]; - if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) || - FT_ALLOC( subr->code[0], data_len ) ) + if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) || + FT_QALLOC( subr->code[0], data_len ) ) goto Fail; if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || - FT_STREAM_READ( subr->code[0], data_len ) ) + FT_STREAM_READ( subr->code[0], data_len ) ) goto Fail; /* set up pointers */ @@ -665,17 +665,18 @@ static FT_Error - cid_hex_to_binary( FT_Byte* data, - FT_ULong data_len, - FT_ULong offset, - CID_Face face ) + cid_hex_to_binary( FT_Byte* data, + FT_ULong data_len, + FT_ULong offset, + CID_Face face, + FT_ULong* data_written ) { FT_Stream stream = face->root.stream; FT_Error error; FT_Byte buffer[256]; FT_Byte *p, *plimit; - FT_Byte *d, *dlimit; + FT_Byte *d = data, *dlimit; FT_Byte val; FT_Bool upper_nibble, done; @@ -684,7 +685,6 @@ if ( FT_STREAM_SEEK( offset ) ) goto Exit; - d = data; dlimit = d + data_len; p = buffer; plimit = p; @@ -758,6 +758,7 @@ error = FT_Err_Ok; Exit: + *data_written = (FT_ULong)( d - data ); return error; } @@ -770,12 +771,11 @@ CID_Parser* parser; FT_Memory memory = face->root.memory; FT_Error error; - FT_Int n; + FT_UInt n; CID_FaceInfo cid = &face->cid; FT_ULong binary_length; - FT_ULong entry_len; cid_init_loader( &loader, face ); @@ -803,8 +803,8 @@ if ( parser->binary_length > face->root.stream->size - parser->data_offset ) { - FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" - " (from %ld to %ld bytes)\n", + FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" )); + FT_TRACE0(( " (from %lu to %lu bytes)\n", parser->binary_length, face->root.stream->size - parser->data_offset )); parser->binary_length = face->root.stream->size - @@ -812,15 +812,16 @@ } /* we must convert the data section from hexadecimal to binary */ - if ( FT_ALLOC( face->binary_data, parser->binary_length ) || + if ( FT_QALLOC( face->binary_data, parser->binary_length ) || FT_SET_ERROR( cid_hex_to_binary( face->binary_data, parser->binary_length, parser->data_offset, - face ) ) ) + face, + &binary_length ) ) ) goto Exit; FT_Stream_OpenMemory( face->cid_stream, - face->binary_data, parser->binary_length ); + face->binary_data, binary_length ); cid->data_offset = 0; } else @@ -831,10 +832,10 @@ /* sanity tests */ - if ( cid->fd_bytes < 0 || cid->gd_bytes < 1 ) + if ( cid->gd_bytes == 0 ) { FT_ERROR(( "cid_face_open:" - " Invalid `FDBytes' or `GDBytes' value\n" )); + " Invalid `GDBytes' value\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } @@ -843,15 +844,32 @@ if ( cid->fd_bytes > 4 || cid->gd_bytes > 4 ) { FT_ERROR(( "cid_face_open:" - " Values of `FDBytes' or `GDBytes' larger than 4\n" - " " + " Values of `FDBytes' or `GDBytes' larger than 4\n" )); + FT_ERROR(( " " " are not supported\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } binary_length = face->cid_stream->size - cid->data_offset; - entry_len = (FT_ULong)( cid->fd_bytes + cid->gd_bytes ); + + if ( cid->cidmap_offset > binary_length ) + { + FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* the initial pre-check prevents the multiplication overflow */ + if ( cid->cid_count > FT_ULONG_MAX / 8 || + cid->cid_count * ( cid->fd_bytes + cid->gd_bytes ) > + binary_length - cid->cidmap_offset ) + { + FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + for ( n = 0; n < cid->num_dicts; n++ ) { @@ -877,8 +895,7 @@ dict->private_dict.blue_fuzz = 1; } - if ( dict->sd_bytes < 0 || - ( dict->num_subrs && dict->sd_bytes < 1 ) ) + if ( dict->num_subrs && dict->sd_bytes == 0 ) { FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" )); error = FT_THROW( Invalid_File_Format ); @@ -901,11 +918,10 @@ goto Exit; } - /* `num_subrs' is scanned as a signed integer */ - if ( (FT_Int)dict->num_subrs < 0 || - ( dict->sd_bytes && - dict->num_subrs > ( binary_length - dict->subrmap_offset ) / - (FT_UInt)dict->sd_bytes ) ) + /* the initial pre-check prevents the multiplication overflow */ + if ( dict->num_subrs > FT_UINT_MAX / 4 || + dict->num_subrs * dict->sd_bytes > + binary_length - dict->subrmap_offset ) { FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" )); error = FT_THROW( Invalid_File_Format ); @@ -913,22 +929,6 @@ } } - if ( cid->cidmap_offset > binary_length ) - { - FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } - - if ( entry_len && - cid->cid_count > - ( binary_length - cid->cidmap_offset ) / entry_len ) - { - FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } - /* we can now safely proceed */ error = cid_read_subrs( face ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidload.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidload.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidload.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidload.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -37,7 +37,7 @@ FT_LOCAL( FT_ULong ) cid_get_offset( FT_Byte** start, - FT_Byte offsize ); + FT_UInt offsize ); FT_LOCAL( FT_Error ) cid_face_open( CID_Face face, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID objects manager (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -157,10 +157,14 @@ cid_size_request( FT_Size size, FT_Size_Request req ) { + FT_Error error; + PSH_Globals_Funcs funcs; - FT_Request_Metrics( size->face, req ); + error = FT_Request_Metrics( size->face, req ); + if ( error ) + goto Exit; funcs = cid_size_get_globals_funcs( (CID_Size)size ); @@ -170,7 +174,8 @@ size->metrics.y_scale, 0, 0 ); - return FT_Err_Ok; + Exit: + return error; } @@ -211,7 +216,7 @@ /* release subrs */ if ( face->subrs ) { - FT_Int n; + FT_UInt n; for ( n = 0; n < cid->num_dicts; n++ ) @@ -479,11 +484,7 @@ /* set default property values, cf. `ftt1drv.h' */ -#ifdef T1_CONFIG_OPTION_OLD_ENGINE - driver->hinting_engine = FT_HINTING_FREETYPE; -#else driver->hinting_engine = FT_HINTING_ADOBE; -#endif driver->no_stem_darkening = TRUE; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID objects manager (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -73,7 +73,11 @@ /* first of all, check the font format in the header */ if ( FT_FRAME_ENTER( 31 ) ) + { + FT_TRACE2(( " not a CID-keyed font\n" )); + error = FT_THROW( Unknown_File_Format ); goto Exit; + } if ( ft_strncmp( (char *)stream->cursor, "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) @@ -181,7 +185,7 @@ parser->root.base = parser->postscript; parser->root.cursor = parser->postscript; parser->root.limit = parser->root.cursor + ps_len; - parser->num_dict = -1; + parser->num_dict = FT_UINT_MAX; /* Finally, we check whether `StartData' or `/sfnts' was real -- */ /* it could be in a comment or string. We also get the arguments */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -78,7 +78,7 @@ FT_ULong binary_length; CID_FaceInfo cid; - FT_Int num_dict; + FT_UInt num_dict; } CID_Parser; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID driver interface (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level CID driver interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * CID token definitions (specification only). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * AFM parser (body). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -29,6 +29,16 @@ /************************************************************************** * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT afmparse + + + /************************************************************************** + * * AFM_Stream * * The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. @@ -586,21 +596,39 @@ static FT_Error afm_parse_track_kern( AFM_Parser parser ) { - AFM_FontInfo fi = parser->FontInfo; + AFM_FontInfo fi = parser->FontInfo; + AFM_Stream stream = parser->stream; AFM_TrackKern tk; - char* key; - FT_Offset len; - int n = -1; - FT_Int tmp; + + char* key; + FT_Offset len; + int n = -1; + FT_Int tmp; if ( afm_parser_read_int( parser, &tmp ) ) goto Fail; if ( tmp < 0 ) + { + FT_ERROR(( "afm_parse_track_kern: invalid number of track kerns\n" )); goto Fail; + } fi->NumTrackKern = (FT_UInt)tmp; + FT_TRACE3(( "afm_parse_track_kern: %u track kern%s expected\n", + fi->NumTrackKern, + fi->NumTrackKern == 1 ? "" : "s" )); + + /* Rough sanity check: The minimum line length of the `TrackKern` */ + /* command is 20 characters (including the EOL character). */ + if ( (FT_ULong)( stream->limit - stream->cursor ) / 20 < + fi->NumTrackKern ) + { + FT_ERROR(( "afm_parse_track_kern:" + " number of track kern entries exceeds stream size\n" )); + goto Fail; + } if ( fi->NumTrackKern ) { @@ -623,7 +651,10 @@ n++; if ( n >= (int)fi->NumTrackKern ) - goto Fail; + { + FT_ERROR(( "afm_parse_track_kern: too many track kern data\n" )); + goto Fail; + } tk = fi->TrackKerns + n; @@ -633,7 +664,12 @@ shared_vals[3].type = AFM_VALUE_TYPE_FIXED; shared_vals[4].type = AFM_VALUE_TYPE_FIXED; if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 ) + { + FT_ERROR(( "afm_parse_track_kern:" + " insufficient number of parameters for entry %d\n", + n )); goto Fail; + } tk->degree = shared_vals[0].u.i; tk->min_ptsize = shared_vals[1].u.f; @@ -646,7 +682,19 @@ case AFM_TOKEN_ENDTRACKKERN: case AFM_TOKEN_ENDKERNDATA: case AFM_TOKEN_ENDFONTMETRICS: - fi->NumTrackKern = (FT_UInt)( n + 1 ); + tmp = n + 1; + if ( (FT_UInt)tmp != fi->NumTrackKern ) + { + FT_TRACE1(( "afm_parse_track_kern: %s%d track kern entr%s seen\n", + tmp == 0 ? "" : "only ", + tmp, + tmp == 1 ? "y" : "ies" )); + fi->NumTrackKern = (FT_UInt)tmp; + } + else + FT_TRACE3(( "afm_parse_track_kern: %d track kern entr%s seen\n", + tmp, + tmp == 1 ? "y" : "ies" )); return FT_Err_Ok; case AFM_TOKEN_UNKNOWN: @@ -667,7 +715,7 @@ /* compare two kerning pairs */ - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) afm_compare_kern_pairs( const void* a, const void* b ) { @@ -690,7 +738,8 @@ static FT_Error afm_parse_kern_pairs( AFM_Parser parser ) { - AFM_FontInfo fi = parser->FontInfo; + AFM_FontInfo fi = parser->FontInfo; + AFM_Stream stream = parser->stream; AFM_KernPair kp; char* key; FT_Offset len; @@ -702,9 +751,26 @@ goto Fail; if ( tmp < 0 ) + { + FT_ERROR(( "afm_parse_kern_pairs: invalid number of kern pairs\n" )); goto Fail; + } fi->NumKernPair = (FT_UInt)tmp; + FT_TRACE3(( "afm_parse_kern_pairs: %u kern pair%s expected\n", + fi->NumKernPair, + fi->NumKernPair == 1 ? "" : "s" )); + + /* Rough sanity check: The minimum line length of the `KP`, */ + /* `KPH`,`KPX`, and `KPY` commands is 10 characters (including */ + /* the EOL character). */ + if ( (FT_ULong)( stream->limit - stream->cursor ) / 10 < + fi->NumKernPair ) + { + FT_ERROR(( "afm_parse_kern_pairs:" + " number of kern pairs exceeds stream size\n" )); + goto Fail; + } if ( fi->NumKernPair ) { @@ -734,7 +800,10 @@ n++; if ( n >= (int)fi->NumKernPair ) + { + FT_ERROR(( "afm_parse_kern_pairs: too many kern pairs\n" )); goto Fail; + } kp = fi->KernPairs + n; @@ -744,7 +813,12 @@ shared_vals[3].type = AFM_VALUE_TYPE_INTEGER; r = afm_parser_read_vals( parser, shared_vals, 4 ); if ( r < 3 ) + { + FT_ERROR(( "afm_parse_kern_pairs:" + " insufficient number of parameters for entry %d\n", + n )); goto Fail; + } /* index values can't be negative */ kp->index1 = shared_vals[0].u.u; @@ -766,7 +840,20 @@ case AFM_TOKEN_ENDKERNPAIRS: case AFM_TOKEN_ENDKERNDATA: case AFM_TOKEN_ENDFONTMETRICS: - fi->NumKernPair = (FT_UInt)( n + 1 ); + tmp = n + 1; + if ( (FT_UInt)tmp != fi->NumKernPair ) + { + FT_TRACE1(( "afm_parse_kern_pairs: %s%d kern pair%s seen\n", + tmp == 0 ? "" : "only ", + tmp, + tmp == 1 ? "" : "s" )); + fi->NumKernPair = (FT_UInt)tmp; + } + else + FT_TRACE3(( "afm_parse_kern_pairs: %d kern pair%s seen\n", + tmp, + tmp == 1 ? "" : "s" )); + ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), afm_compare_kern_pairs ); @@ -792,22 +879,43 @@ char* key; FT_Offset len; + int have_trackkern = 0; + int have_kernpairs = 0; + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) { switch ( afm_tokenize( key, len ) ) { case AFM_TOKEN_STARTTRACKKERN: + if ( have_trackkern ) + { + FT_ERROR(( "afm_parse_kern_data:" + " invalid second horizontal track kern section\n" )); + goto Fail; + } + error = afm_parse_track_kern( parser ); if ( error ) return error; + + have_trackkern = 1; break; case AFM_TOKEN_STARTKERNPAIRS: case AFM_TOKEN_STARTKERNPAIRS0: + if ( have_kernpairs ) + { + FT_ERROR(( "afm_parse_kern_data:" + " invalid second horizontal kern pair section\n" )); + goto Fail; + } + error = afm_parse_kern_pairs( parser ); if ( error ) return error; + + have_kernpairs = 1; break; case AFM_TOKEN_ENDKERNDATA: diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * AFM parser (specification). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (body). * - * Copyright (C) 2017-2020 by + * Copyright (C) 2017-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -1871,7 +1871,7 @@ case cff_op_put: { FT_Fixed val = args[0]; - FT_Int idx = (FT_Int)( args[1] >> 16 ); + FT_UInt idx = (FT_UInt)( args[1] >> 16 ); FT_TRACE4(( " put\n" )); @@ -1880,20 +1880,20 @@ /* didn't give a hard-coded size limit of the temporary */ /* storage array; instead, an argument of the */ /* `MultipleMaster' operator set the size */ - if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS ) + if ( idx < CFF_MAX_TRANS_ELEMENTS ) decoder->buildchar[idx] = val; } break; case cff_op_get: { - FT_Int idx = (FT_Int)( args[0] >> 16 ); + FT_UInt idx = (FT_UInt)( args[0] >> 16 ); FT_Fixed val = 0; FT_TRACE4(( " get\n" )); - if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS ) + if ( idx < CFF_MAX_TRANS_ELEMENTS ) val = decoder->buildchar[idx]; args[0] = val; @@ -1914,9 +1914,9 @@ /* this operator was removed from the Type2 specification */ /* in version 16-March-2000 */ { - FT_Int reg_idx = (FT_Int)args[0]; - FT_Int idx = (FT_Int)args[1]; - FT_Int count = (FT_Int)args[2]; + FT_UInt reg_idx = (FT_UInt)args[0]; + FT_UInt idx = (FT_UInt)args[1]; + FT_UInt count = (FT_UInt)args[2]; FT_TRACE4(( " load\n" )); @@ -1924,11 +1924,11 @@ /* since we currently don't handle interpolation of multiple */ /* master fonts, we store a vector [1 0 0 ...] in the */ /* temporary storage array regardless of the Registry index */ - if ( reg_idx >= 0 && reg_idx <= 2 && - idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS && - count >= 0 && count <= num_axes ) + if ( reg_idx <= 2 && + idx < CFF_MAX_TRANS_ELEMENTS && + count <= num_axes ) { - FT_Int end, i; + FT_UInt end, i; end = FT_MIN( idx + count, CFF_MAX_TRANS_ELEMENTS ); @@ -2153,7 +2153,7 @@ decoder->locals_bias ); - FT_TRACE4(( " callsubr (idx %d, entering level %d)\n", + FT_TRACE4(( " callsubr (idx %d, entering level %ld)\n", idx, zone - decoder->zones + 1 )); @@ -2197,7 +2197,7 @@ decoder->globals_bias ); - FT_TRACE4(( " callgsubr (idx %d, entering level %d)\n", + FT_TRACE4(( " callgsubr (idx %d, entering level %ld)\n", idx, zone - decoder->zones + 1 )); @@ -2236,7 +2236,7 @@ break; case cff_op_return: - FT_TRACE4(( " return (leaving level %d)\n", + FT_TRACE4(( " return (leaving level %ld)\n", decoder->zone - decoder->zones )); if ( decoder->zone <= decoder->zones ) @@ -2271,7 +2271,8 @@ } /* while ip < limit */ - FT_TRACE4(( "..end..\n\n" )); + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); Fail: return error; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (specification). * - * Copyright (C) 2017-2020 by + * Copyright (C) 2017-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psarrst.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psarrst.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psarrst.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psarrst.c 2022-07-14 08:05:38.000000000 +0000 @@ -65,7 +65,6 @@ arrstack->error = error; arrstack->sizeItem = sizeItem; arrstack->allocated = 0; - arrstack->chunk = 10; /* chunks of 10 items */ arrstack->count = 0; arrstack->totalSize = 0; arrstack->ptr = NULL; @@ -110,7 +109,7 @@ FT_ASSERT( newSize > 0 ); /* avoid realloc with zero size */ - if ( !FT_REALLOC( arrstack->ptr, arrstack->totalSize, newSize ) ) + if ( !FT_QREALLOC( arrstack->ptr, arrstack->totalSize, newSize ) ) { arrstack->allocated = numElements; arrstack->totalSize = newSize; @@ -216,9 +215,9 @@ if ( arrstack->count == arrstack->allocated ) { - /* grow the buffer by one chunk */ + /* increase the buffer size */ if ( !cf2_arrstack_setNumElements( - arrstack, arrstack->allocated + arrstack->chunk ) ) + arrstack, arrstack->allocated * 2 + 16 ) ) { /* on error, ignore the push */ return; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psarrst.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psarrst.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psarrst.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psarrst.h 2022-07-14 08:05:38.000000000 +0000 @@ -55,7 +55,6 @@ size_t sizeItem; /* bytes per element */ size_t allocated; /* items allocated */ - size_t chunk; /* allocation increment in items */ size_t count; /* number of elements allocated */ size_t totalSize; /* total bytes allocated */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PS auxiliary module error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (body). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (specification). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psblues.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psblues.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psblues.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psblues.c 2022-07-14 08:05:38.000000000 +0000 @@ -506,7 +506,8 @@ /* guarantee minimum of 1 pixel overshoot */ dsNew = FT_MIN( cf2_fixedRound( bottomHintEdge->dsCoord ), - blues->zone[i].dsFlatEdge - cf2_intToFixed( 1 ) ); + SUB_INT32( blues->zone[i].dsFlatEdge, + cf2_intToFixed( 1 ) ) ); } else diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Some convenience conversions (body). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Some convenience conversions (specification). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psft.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psft.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psft.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psft.c 2022-07-14 08:05:38.000000000 +0000 @@ -742,13 +742,13 @@ /* For ordinary fonts get the character data stored in the face record. */ { glyph_data.pointer = type1->charstrings[glyph_index]; - glyph_data.length = (FT_Int)type1->charstrings_len[glyph_index]; + glyph_data.length = type1->charstrings_len[glyph_index]; } if ( !error ) { FT_Byte* charstring_base = (FT_Byte*)glyph_data.pointer; - FT_ULong charstring_len = (FT_ULong)glyph_data.length; + FT_ULong charstring_len = glyph_data.length; FT_ASSERT( charstring_base + charstring_len >= charstring_base ); @@ -778,7 +778,7 @@ face = (T1_Face)decoder->builder.face; data.pointer = buf->start; - data.length = (FT_Int)( buf->end - buf->start ); + data.length = (FT_UInt)( buf->end - buf->start ); if ( face->root.internal->incremental_interface ) face->root.internal->incremental_interface->funcs->free_glyph_data( diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/pshints.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/pshints.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/pshints.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/pshints.c 2022-07-14 08:05:38.000000000 +0000 @@ -412,6 +412,12 @@ { FT_Bool isPair = cf2_hint_isPair( &hintmap->edge[i] ); + /* final amount to move edge or edge pair */ + CF2_Fixed move = 0; + + CF2_Fixed dsCoord_i; + CF2_Fixed dsCoord_j; + /* index of upper edge (same value for ghost hint) */ j = isPair ? i + 1 : i; @@ -422,11 +428,14 @@ FT_ASSERT( cf2_hint_isLocked( &hintmap->edge[i] ) == cf2_hint_isLocked( &hintmap->edge[j] ) ); + dsCoord_i = hintmap->edge[i].dsCoord; + dsCoord_j = hintmap->edge[j].dsCoord; + if ( !cf2_hint_isLocked( &hintmap->edge[i] ) ) { /* hint edge is not locked, we can adjust it */ - CF2_Fixed fracDown = cf2_fixedFraction( hintmap->edge[i].dsCoord ); - CF2_Fixed fracUp = cf2_fixedFraction( hintmap->edge[j].dsCoord ); + CF2_Fixed fracDown = cf2_fixedFraction( dsCoord_i ); + CF2_Fixed fracUp = cf2_fixedFraction( dsCoord_j ); /* calculate all four possibilities; moves down are negative */ CF2_Fixed downMoveDown = 0 - fracDown; @@ -443,9 +452,6 @@ /* smallest move down */ CF2_Fixed moveDown = FT_MAX( downMoveDown, upMoveDown ); - /* final amount to move edge or edge pair */ - CF2_Fixed move; - CF2_Fixed downMinCounter = CF2_MIN_COUNTER; CF2_Fixed upMinCounter = CF2_MIN_COUNTER; FT_Bool saveEdge = FALSE; @@ -467,16 +473,14 @@ /* is there room to move up? */ /* there is if we are at top of array or the next edge is at or */ /* beyond proposed move up? */ - if ( j >= hintmap->count - 1 || + if ( j >= hintmap->count - 1 || hintmap->edge[j + 1].dsCoord >= - ADD_INT32( hintmap->edge[j].dsCoord, - moveUp + upMinCounter ) ) + ADD_INT32( dsCoord_j, moveUp + upMinCounter ) ) { /* there is room to move up; is there also room to move down? */ - if ( i == 0 || + if ( i == 0 || hintmap->edge[i - 1].dsCoord <= - ADD_INT32( hintmap->edge[i].dsCoord, - moveDown - downMinCounter ) ) + ADD_INT32( dsCoord_i, moveDown - downMinCounter ) ) { /* move smaller absolute amount */ move = ( -moveDown < moveUp ) ? moveDown : moveUp; /* optimum */ @@ -487,10 +491,9 @@ else { /* is there room to move down? */ - if ( i == 0 || + if ( i == 0 || hintmap->edge[i - 1].dsCoord <= - ADD_INT32( hintmap->edge[i].dsCoord, - moveDown - downMinCounter ) ) + ADD_INT32( dsCoord_i, moveDown - downMinCounter ) ) { move = moveDown; /* true if non-optimum move */ @@ -524,17 +527,21 @@ } /* move the edge(s) */ - hintmap->edge[i].dsCoord = ADD_INT32( hintmap->edge[i].dsCoord, - move ); + hintmap->edge[i].dsCoord = ADD_INT32( dsCoord_i, move ); if ( isPair ) - hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord, - move ); + hintmap->edge[j].dsCoord = ADD_INT32( dsCoord_j, move ); } - /* assert there are no overlaps in device space */ + /* assert there are no overlaps in device space; */ + /* ignore tests if there was overflow (that is, if */ + /* operands have the same sign but the sum does not) */ FT_ASSERT( i == 0 || + ( ( dsCoord_i ^ move ) >= 0 && + ( dsCoord_i ^ hintmap->edge[i].dsCoord ) < 0 ) || hintmap->edge[i - 1].dsCoord <= hintmap->edge[i].dsCoord ); FT_ASSERT( i < j || + ( ( dsCoord_j ^ move ) >= 0 && + ( dsCoord_j ^ hintmap->edge[j].dsCoord ) < 0 ) || hintmap->edge[i].dsCoord <= hintmap->edge[j].dsCoord ); /* adjust the scales, avoiding divide by zero */ @@ -1022,10 +1029,17 @@ } } - FT_TRACE6(( "%s\n", initialMap ? "flags: [p]air [g]host [t]op" - " [b]ottom [L]ocked [S]ynthetic\n" - "Initial hintmap" - : "Hints:" )); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( initialMap ) + { + FT_TRACE6(( "flags: [p]air [g]host [t]op" + " [b]ottom [L]ocked [S]ynthetic\n" )); + FT_TRACE6(( "Initial hintmap" )); + } + else + FT_TRACE6(( "Hints:" )); +#endif + cf2_hintmap_dump( hintmap ); /* diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c 2022-07-14 08:05:38.000000000 +0000 @@ -469,7 +469,7 @@ */ FT_LOCAL_DEF( void ) cf2_interpT2CharString( CF2_Font font, - CF2_Buffer buf, + const CF2_Buffer buf, CF2_OutlineCallbacks callbacks, const FT_Vector* translation, FT_Bool doingSeac, @@ -1340,9 +1340,9 @@ if ( decoder->glyph_names == 0 ) #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { - FT_ERROR(( - "cf2_interpT2CharString: (Type 1 seac)" - " glyph names table not available in this font\n" )); + FT_ERROR(( "cf2_interpT2CharString:\n" )); + FT_ERROR(( " (Type 1 seac) glyph names table" + " not available in this font\n" )); lastError = FT_THROW( Invalid_Glyph_Format ); goto exit; } @@ -1368,9 +1368,9 @@ if ( bchar_index < 0 || achar_index < 0 ) { - FT_ERROR(( - "cf2_interpT2CharString: (Type 1 seac)" - " invalid seac character code arguments\n" )); + FT_ERROR(( "cf2_interpT2CharString:\n" )); + FT_ERROR(( " (Type 1 seac) invalid" + " seac character code arguments\n" )); lastError = FT_THROW( Invalid_Glyph_Format ); goto exit; } @@ -1670,7 +1670,13 @@ */ count = cf2_stack_count( opStack ); - FT_ASSERT( (CF2_UInt)arg_cnt <= count ); + if ( (CF2_UInt)arg_cnt > count ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " stack underflow\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } opIdx += count - (CF2_UInt)arg_cnt; @@ -1893,24 +1899,25 @@ /* cvi( ) of BuildCharArray with */ /* WeightVector */ { - FT_Int idx; - PS_Blend blend = decoder->blend; + FT_UInt idx; + PS_Blend blend = decoder->blend; + FT_UInt len_buildchar = decoder->len_buildchar; if ( arg_cnt != 1 || !blend ) goto Unexpected_OtherSubr; - idx = cf2_stack_popInt( opStack ); + idx = (FT_UInt)cf2_stack_popInt( opStack ); - if ( idx < 0 || - (FT_UInt)idx + blend->num_designs > - decoder->len_buildchar ) + if ( len_buildchar < blend->num_designs || + len_buildchar - blend->num_designs < idx ) goto Unexpected_OtherSubr; - ft_memcpy( &decoder->buildchar[idx], - blend->weight_vector, - blend->num_designs * - sizeof ( blend->weight_vector[0] ) ); + if ( decoder->buildchar && blend->weight_vector ) + ft_memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof ( blend->weight_vector[0] ) ); } break; @@ -2004,17 +2011,16 @@ /* 2 24 callothersubr */ /* ==> set BuildCharArray[cvi( )] = */ { - CF2_Int idx; + CF2_UInt idx; PS_Blend blend = decoder->blend; if ( arg_cnt != 2 || !blend ) goto Unexpected_OtherSubr; - idx = cf2_stack_popInt( opStack ); + idx = (CF2_UInt)cf2_stack_popInt( opStack ); - if ( idx < 0 || - (FT_UInt)idx >= decoder->len_buildchar ) + if ( idx >= decoder->len_buildchar ) goto Unexpected_OtherSubr; decoder->buildchar[idx] = @@ -2027,17 +2033,16 @@ /* ==> push BuildCharArray[cvi( idx )] */ /* onto T1 stack */ { - CF2_Int idx; + CF2_UInt idx; PS_Blend blend = decoder->blend; if ( arg_cnt != 1 || !blend ) goto Unexpected_OtherSubr; - idx = cf2_stack_popInt( opStack ); + idx = (CF2_UInt)cf2_stack_popInt( opStack ); - if ( idx < 0 || - (FT_UInt)idx >= decoder->len_buildchar ) + if ( idx >= decoder->len_buildchar ) goto Unexpected_OtherSubr; cf2_stack_pushFixed( opStack, @@ -2179,29 +2184,29 @@ case cf2_escPUT: { CF2_F16Dot16 val; - CF2_Int idx; + CF2_UInt idx; FT_TRACE4(( " put\n" )); - idx = cf2_stack_popInt( opStack ); + idx = (CF2_UInt)cf2_stack_popInt( opStack ); val = cf2_stack_popFixed( opStack ); - if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) + if ( idx < CF2_STORAGE_SIZE ) storage[idx] = val; } continue; /* do not clear the stack */ case cf2_escGET: { - CF2_Int idx; + CF2_UInt idx; FT_TRACE4(( " get\n" )); - idx = cf2_stack_popInt( opStack ); + idx = (CF2_UInt)cf2_stack_popInt( opStack ); - if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) + if ( idx < CF2_STORAGE_SIZE ) cf2_stack_pushFixed( opStack, storage[idx] ); } continue; /* do not clear the stack */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.h 2022-07-14 08:05:38.000000000 +0000 @@ -65,7 +65,7 @@ FT_LOCAL( void ) cf2_interpT2CharString( CF2_Font font, - CF2_Buffer charstring, + const CF2_Buffer buf, CF2_OutlineCallbacks callbacks, const FT_Vector* translation, FT_Bool doingSeac, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -99,45 +99,31 @@ } - static void - shift_elements( PS_Table table, - FT_Byte* old_base ) - { - FT_PtrDist delta = table->block - old_base; - FT_Byte** offset = table->elements; - FT_Byte** limit = offset + table->max_elems; - - - for ( ; offset < limit; offset++ ) - { - if ( offset[0] ) - offset[0] += delta; - } - } - - static FT_Error - reallocate_t1_table( PS_Table table, - FT_Offset new_size ) + ps_table_realloc( PS_Table table, + FT_Offset new_size ) { FT_Memory memory = table->memory; FT_Byte* old_base = table->block; FT_Error error; - /* allocate new base block */ - if ( FT_ALLOC( table->block, new_size ) ) - { - table->block = old_base; + /* (re)allocate the base block */ + if ( FT_REALLOC( table->block, table->capacity, new_size ) ) return error; - } - /* copy elements and shift offsets */ - if ( old_base ) + /* rebase offsets if necessary */ + if ( old_base && table->block != old_base ) { - FT_MEM_COPY( table->block, old_base, table->capacity ); - shift_elements( table, old_base ); - FT_FREE( old_base ); + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + + for ( ; offset < limit; offset++ ) + { + if ( *offset ) + *offset = table->block + ( *offset - old_base ); + } } table->capacity = new_size; @@ -204,7 +190,7 @@ new_size = FT_PAD_CEIL( new_size, 1024 ); } - error = reallocate_t1_table( table, new_size ); + error = ps_table_realloc( table, new_size ); if ( error ) return error; @@ -234,32 +220,12 @@ * @InOut: * table :: * The target table. - * - * @Note: - * This function does NOT release the heap's memory block. It is up - * to the caller to clean it, or reference it in its own structures. */ FT_LOCAL_DEF( void ) ps_table_done( PS_Table table ) { - FT_Memory memory = table->memory; - FT_Error error; - FT_Byte* old_base = table->block; - - - /* should never fail, because rec.cursor <= rec.size */ - if ( !old_base ) - return; - - if ( FT_ALLOC( table->block, table->cursor ) ) - return; - FT_MEM_COPY( table->block, old_base, table->cursor ); - shift_elements( table, old_base ); - - table->capacity = table->cursor; - FT_FREE( old_base ); - - FT_UNUSED( error ); + /* no problem if shrinking fails */ + ps_table_realloc( table, table->cursor ); } @@ -595,10 +561,10 @@ if ( cur < limit && cur == parser->cursor ) { FT_ERROR(( "ps_parser_skip_PS_token:" - " current token is `%c' which is self-delimiting\n" - " " - " but invalid at this point\n", + " current token is `%c' which is self-delimiting\n", *cur )); + FT_ERROR(( " " + " but invalid at this point\n" )); error = FT_THROW( Invalid_File_Format ); } @@ -979,7 +945,7 @@ } len = (FT_UInt)( cur - *cursor ); - if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) + if ( cur >= limit || FT_QALLOC( result, len + 1 ) ) return 0; /* now copy the string */ @@ -1098,7 +1064,6 @@ { FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; FT_Long val; - FT_String* string = NULL; skip_spaces( &cur, limit ); @@ -1148,8 +1113,9 @@ case T1_FIELD_TYPE_STRING: case T1_FIELD_TYPE_KEY: { - FT_Memory memory = parser->memory; - FT_UInt len = (FT_UInt)( limit - cur ); + FT_Memory memory = parser->memory; + FT_UInt len = (FT_UInt)( limit - cur ); + FT_String* string = NULL; if ( cur >= limit ) @@ -1175,8 +1141,8 @@ else { FT_ERROR(( "ps_parser_load_field:" - " expected a name or string\n" - " " + " expected a name or string\n" )); + FT_ERROR(( " " " but found token of type %d instead\n", token.type )); error = FT_THROW( Invalid_File_Format ); @@ -1190,10 +1156,9 @@ FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", field->ident )); FT_FREE( *(FT_String**)q ); - *(FT_String**)q = NULL; } - if ( FT_ALLOC( string, len + 1 ) ) + if ( FT_QALLOC( string, len + 1 ) ) goto Exit; FT_MEM_COPY( string, cur, len ); @@ -1248,7 +1213,7 @@ FT_UInt i; - if ( FT_NEW_ARRAY( temp, max_objects * 4 ) ) + if ( FT_QNEW_ARRAY( temp, max_objects * 4 ) ) goto Exit; for ( i = 0; i < 4; i++ ) @@ -1258,14 +1223,14 @@ if ( result < 0 || (FT_UInt)result < max_objects ) { FT_ERROR(( "ps_parser_load_field:" - " expected %d integer%s in the %s subarray\n" - " " - " of /FontBBox in the /Blend dictionary\n", + " expected %d integer%s in the %s subarray\n", max_objects, max_objects > 1 ? "s" : "", i == 0 ? "first" : ( i == 1 ? "second" : ( i == 2 ? "third" : "fourth" ) ) )); + FT_ERROR(( " " + " of /FontBBox in the /Blend dictionary\n" )); error = FT_THROW( Invalid_File_Format ); FT_FREE( temp ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psstack.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psstack.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/psstack.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/psstack.c 2022-07-14 08:05:38.000000000 +0000 @@ -54,20 +54,18 @@ FT_Error* e, FT_UInt stackSize ) { - FT_Error error = FT_Err_Ok; /* for FT_NEW */ - + FT_Error error; /* for FT_QNEW */ CF2_Stack stack = NULL; - if ( FT_NEW( stack ) ) + if ( FT_QNEW( stack ) ) return NULL; - /* initialize the structure; FT_NEW zeroes it */ stack->memory = memory; stack->error = e; /* allocate the stack buffer */ - if ( FT_NEW_ARRAY( stack->buffer, stackSize ) ) + if ( FT_QNEW_ARRAY( stack->buffer, stackSize ) ) { FT_FREE( stack ); return NULL; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 character map support (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 character map support (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (body). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -27,8 +27,11 @@ #include "psauxerr.h" + /* ensure proper sign extension */ -#define Fix2Int( f ) ( (FT_Int)(FT_Short)( (f) >> 16 ) ) +#define Fix2Int( f ) ( (FT_Int) (FT_Short)( (f) >> 16 ) ) +#define Fix2UInt( f ) ( (FT_UInt)(FT_Short)( (f) >> 16 ) ) + /************************************************************************** * @@ -517,7 +520,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( bol ) { - FT_TRACE5(( " (%d)", decoder->top - decoder->stack )); + FT_TRACE5(( " (%ld)", decoder->top - decoder->stack )); bol = FALSE; } #endif @@ -1025,16 +1028,16 @@ /* 2 24 callothersubr */ /* ==> set BuildCharArray[cvi( )] = */ { - FT_Int idx; + FT_UInt idx; PS_Blend blend = decoder->blend; if ( arg_cnt != 2 || !blend ) goto Unexpected_OtherSubr; - idx = Fix2Int( top[1] ); + idx = Fix2UInt( top[1] ); - if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) + if ( idx >= decoder->len_buildchar ) goto Unexpected_OtherSubr; decoder->buildchar[idx] = top[0]; @@ -1046,16 +1049,16 @@ /* ==> push BuildCharArray[cvi( idx )] */ /* onto T1 stack */ { - FT_Int idx; + FT_UInt idx; PS_Blend blend = decoder->blend; if ( arg_cnt != 1 || !blend ) goto Unexpected_OtherSubr; - idx = Fix2Int( top[0] ); + idx = Fix2UInt( top[0] ); - if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) + if ( idx >= decoder->len_buildchar ) goto Unexpected_OtherSubr; top[0] = decoder->buildchar[idx]; @@ -1162,9 +1165,9 @@ if ( top - decoder->stack != num_args ) FT_TRACE0(( "t1_decoder_parse_charstrings:" " too much operands on the stack" - " (seen %d, expected %d)\n", + " (seen %ld, expected %d)\n", top - decoder->stack, num_args )); - break; + break; } #endif /* FT_DEBUG_LEVEL_TRACE */ @@ -1209,7 +1212,7 @@ FT_TRACE4(( "BuildCharArray = [ " )); for ( i = 0; i < decoder->len_buildchar; i++ ) - FT_TRACE4(( "%d ", decoder->buildchar[i] )); + FT_TRACE4(( "%ld ", decoder->buildchar[i] )); FT_TRACE4(( "]\n" )); } @@ -1650,7 +1653,8 @@ } /* while ip < limit */ - FT_TRACE4(( "..end..\n\n" )); + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); Fail: return error; @@ -2070,7 +2074,8 @@ } /* while ip < limit */ - FT_TRACE4(( "..end..\n\n" )); + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); No_Width: FT_ERROR(( "t1_decoder_parse_metrics:" diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (specification). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (body). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -182,13 +182,13 @@ count = hints->num_hints; /* allocate our tables */ - if ( FT_NEW_ARRAY( table->sort, 2 * count ) || - FT_NEW_ARRAY( table->hints, count ) || - FT_NEW_ARRAY( table->zones, 2 * count + 1 ) ) + if ( FT_QNEW_ARRAY( table->sort, 2 * count ) || + FT_QNEW_ARRAY( table->hints, count ) || + FT_QNEW_ARRAY( table->zones, 2 * count + 1 ) ) goto Exit; table->max_hints = count; - table->sort_global = table->sort + count; + table->sort_global = FT_OFFSET( table->sort, count ); table->num_hints = 0; table->num_zones = 0; table->zone = NULL; @@ -305,17 +305,18 @@ /* now, sort the hints; they are guaranteed to not overlap */ /* so we can compare their "org_pos" field directly */ { - FT_Int i1, i2; + FT_UInt i1, i2; PSH_Hint hint1, hint2; PSH_Hint* sort = table->sort; /* a simple bubble sort will do, since in 99% of cases, the hints */ /* will be already sorted -- and the sort will be linear */ - for ( i1 = 1; i1 < (FT_Int)count; i1++ ) + for ( i1 = 1; i1 < count; i1++ ) { hint1 = sort[i1]; - for ( i2 = i1 - 1; i2 >= 0; i2-- ) + /* this loop stops when i2 wraps around after reaching 0 */ + for ( i2 = i1 - 1; i2 < i1; i2-- ) { hint2 = sort[i2]; @@ -869,7 +870,7 @@ return; } -#endif /* DEBUG_HINTER*/ +#endif /* DEBUG_HINTER */ hint = table->hints; count = table->max_hints; @@ -1049,12 +1050,12 @@ } - static int + static PSH_Dir psh_compute_dir( FT_Pos dx, FT_Pos dy ) { - FT_Pos ax, ay; - int result = PSH_DIR_NONE; + FT_Pos ax, ay; + PSH_Dir result = PSH_DIR_NONE; ax = FT_ABS( dx ); @@ -1166,8 +1167,8 @@ memory = glyph->memory = globals->memory; /* allocate and setup points + contours arrays */ - if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) || - FT_NEW_ARRAY( glyph->contours, outline->n_contours ) ) + if ( FT_QNEW_ARRAY( glyph->points, outline->n_points ) || + FT_QNEW_ARRAY( glyph->contours, outline->n_contours ) ) goto Exit; glyph->num_points = (FT_UInt)outline->n_points; @@ -1227,28 +1228,29 @@ FT_Pos dxi, dyi, dxo, dyo; + point->flags = 0; if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) ) - point->flags = PSH_POINT_OFF; + psh_point_set_off( point ); dxi = vec[n].x - vec[n_prev].x; dyi = vec[n].y - vec[n_prev].y; - point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi ); + point->dir_in = psh_compute_dir( dxi, dyi ); dxo = vec[n_next].x - vec[n].x; dyo = vec[n_next].y - vec[n].y; - point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo ); + point->dir_out = psh_compute_dir( dxo, dyo ); /* detect smooth points */ - if ( point->flags & PSH_POINT_OFF ) - point->flags |= PSH_POINT_SMOOTH; + if ( psh_point_is_off( point ) ) + psh_point_set_smooth( point ); else if ( point->dir_in == point->dir_out ) { if ( point->dir_out != PSH_DIR_NONE || psh_corner_is_flat( dxi, dyi, dxo, dyo ) ) - point->flags |= PSH_POINT_SMOOTH; + psh_point_set_smooth( point ); } } } @@ -1403,16 +1405,13 @@ } - /* major_dir is the direction for points on the bottom/left of the stem; */ - /* Points on the top/right of the stem will have a direction of */ - /* -major_dir. */ - + /* the min and max are based on contour orientation and fill rule */ static void psh_hint_table_find_strong_points( PSH_Hint_Table table, PSH_Point point, FT_UInt count, FT_Int threshold, - FT_Int major_dir ) + PSH_Dir major_dir ) { PSH_Hint* sort = table->sort; FT_UInt num_hints = table->num_hints; @@ -1420,59 +1419,53 @@ for ( ; count > 0; count--, point++ ) { - FT_Int point_dir = 0; - FT_Pos org_u = point->org_u; + PSH_Dir point_dir; + FT_Pos org_u = point->org_u; if ( psh_point_is_strong( point ) ) continue; - if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) ) - point_dir = point->dir_in; - - else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) ) - point_dir = point->dir_out; + point_dir = + (PSH_Dir)( ( point->dir_in | point->dir_out ) & major_dir ); - if ( point_dir ) + if ( point_dir & ( PSH_DIR_DOWN | PSH_DIR_RIGHT ) ) { - if ( point_dir == major_dir ) - { - FT_UInt nn; + FT_UInt nn; - for ( nn = 0; nn < num_hints; nn++ ) - { - PSH_Hint hint = sort[nn]; - FT_Pos d = org_u - hint->org_pos; + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; - if ( d < threshold && -d < threshold ) - { - psh_point_set_strong( point ); - point->flags2 |= PSH_POINT_EDGE_MIN; - point->hint = hint; - break; - } + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + break; } } - else if ( point_dir == -major_dir ) - { - FT_UInt nn; + } + else if ( point_dir & ( PSH_DIR_UP | PSH_DIR_LEFT ) ) + { + FT_UInt nn; - for ( nn = 0; nn < num_hints; nn++ ) - { - PSH_Hint hint = sort[nn]; - FT_Pos d = org_u - hint->org_pos - hint->org_len; + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; - if ( d < threshold && -d < threshold ) - { - psh_point_set_strong( point ); - point->flags2 |= PSH_POINT_EDGE_MAX; - point->hint = hint; - break; - } + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + break; } } } @@ -1555,8 +1548,9 @@ /* the accepted shift for strong points in fractional pixels */ #define PSH_STRONG_THRESHOLD 32 - /* the maximum shift value in font units */ -#define PSH_STRONG_THRESHOLD_MAXIMUM 30 + /* the maximum shift value in font units tuned to distinguish */ + /* between stems and serifs in URW+ font collection */ +#define PSH_STRONG_THRESHOLD_MAXIMUM 12 /* find strong points in a glyph */ @@ -1571,7 +1565,7 @@ PS_Mask mask = table->hint_masks->masks; FT_UInt num_masks = table->hint_masks->num_masks; FT_UInt first = 0; - FT_Int major_dir = ( dimension == 0 ) ? PSH_DIR_VERTICAL + PSH_Dir major_dir = ( dimension == 0 ) ? PSH_DIR_VERTICAL : PSH_DIR_HORIZONTAL; PSH_Dimension dim = &glyph->globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; @@ -1656,8 +1650,8 @@ /* check tangents */ - if ( !PSH_DIR_COMPARE( point->dir_in, PSH_DIR_HORIZONTAL ) && - !PSH_DIR_COMPARE( point->dir_out, PSH_DIR_HORIZONTAL ) ) + if ( !( point->dir_in & PSH_DIR_HORIZONTAL ) && + !( point->dir_out & PSH_DIR_HORIZONTAL ) ) continue; /* skip strong points */ @@ -1805,7 +1799,7 @@ FT_Error error; - if ( FT_NEW_ARRAY( strongs, num_strongs ) ) + if ( FT_QNEW_ARRAY( strongs, num_strongs ) ) return; } @@ -2118,14 +2112,17 @@ FT_Fixed old_x_scale = x_scale; FT_Fixed old_y_scale = y_scale; - FT_Fixed scaled; - FT_Fixed fitted; + FT_Fixed scaled = 0; + FT_Fixed fitted = 0; FT_Bool rescale = FALSE; - scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); - fitted = FT_PIX_ROUND( scaled ); + if ( globals->blues.normal_top.count ) + { + scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); + fitted = FT_PIX_ROUND( scaled ); + } if ( fitted != 0 && scaled != fitted ) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (specification). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -93,21 +93,17 @@ typedef struct PSH_PointRec_* PSH_Point; typedef struct PSH_ContourRec_* PSH_Contour; - enum + typedef enum PSH_Dir_ { - PSH_DIR_NONE = 4, - PSH_DIR_UP = -1, - PSH_DIR_DOWN = 1, - PSH_DIR_LEFT = -2, - PSH_DIR_RIGHT = 2 - }; - -#define PSH_DIR_HORIZONTAL 2 -#define PSH_DIR_VERTICAL 1 - -#define PSH_DIR_COMPARE( d1, d2 ) ( (d1) == (d2) || (d1) == -(d2) ) -#define PSH_DIR_IS_HORIZONTAL( d ) PSH_DIR_COMPARE( d, PSH_DIR_HORIZONTAL ) -#define PSH_DIR_IS_VERTICAL( d ) PSH_DIR_COMPARE( d, PSH_DIR_VERTICAL ) + PSH_DIR_NONE = 0, + PSH_DIR_UP = 1, + PSH_DIR_DOWN = 2, + PSH_DIR_VERTICAL = 1 | 2, + PSH_DIR_LEFT = 4, + PSH_DIR_RIGHT = 8, + PSH_DIR_HORIZONTAL = 4 | 8 + + } PSH_Dir; /* the following bit-flags are computed once by the glyph */ @@ -160,8 +156,8 @@ PSH_Contour contour; FT_UInt flags; FT_UInt flags2; - FT_Char dir_in; - FT_Char dir_out; + PSH_Dir dir_in; + PSH_Dir dir_out; PSH_Hint hint; FT_Pos org_u; FT_Pos org_v; @@ -199,10 +195,6 @@ PSH_Globals globals; PSH_Hint_TableRec hint_tables[2]; - FT_Bool vertical; - FT_Int major_dir; - FT_Int minor_dir; - FT_Bool do_horz_hints; FT_Bool do_vert_hints; FT_Bool do_horz_snapping; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * PostScript hinter global hinting management (body). * Inspired by the new auto-hinter module. * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -650,7 +650,7 @@ FT_Error error; - if ( !FT_NEW( globals ) ) + if ( !FT_QNEW( globals ) ) { FT_UInt count; FT_Short* read; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript hinter global hinting management. * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType PostScript hinter module implementation (body). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript hinter module interface (specification). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PS Hinter error codes (specification only). * - * Copyright (C) 2003-2020 by + * Copyright (C) 2003-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType PostScript hints recorder (body). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -63,16 +63,14 @@ { FT_UInt old_max = table->max_hints; FT_UInt new_max = count; - FT_Error error = FT_Err_Ok; + FT_Error error; - if ( new_max > old_max ) - { - /* try to grow the table */ - new_max = FT_PAD_CEIL( new_max, 8 ); - if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) ) - table->max_hints = new_max; - } + /* try to grow the table */ + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_QRENEW_ARRAY( table->hints, old_max, new_max ) ) + table->max_hints = new_max; + return error; } @@ -90,17 +88,14 @@ count = table->num_hints; count++; - if ( count >= table->max_hints ) + if ( count > table->max_hints ) { error = ps_hint_table_ensure( table, count, memory ); if ( error ) goto Exit; } - hint = table->hints + count - 1; - hint->pos = 0; - hint->len = 0; - hint->flags = 0; + hint = table->hints + count - 1; /* initialized upstream */ table->num_hints = count; @@ -136,14 +131,15 @@ FT_UInt count, FT_Memory memory ) { - FT_UInt old_max = ( mask->max_bits + 7 ) >> 3; - FT_UInt new_max = ( count + 7 ) >> 3; + FT_UInt old_max = mask->max_bits >> 3; + FT_UInt new_max = ( count + 7 ) >> 3; FT_Error error = FT_Err_Ok; if ( new_max > old_max ) { new_max = FT_PAD_CEIL( new_max, 8 ); + /* added bytes are zeroed here */ if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) ) mask->max_bits = new_max * 8; } @@ -154,31 +150,15 @@ /* test a bit value in a given mask */ static FT_Int ps_mask_test_bit( PS_Mask mask, - FT_Int idx ) + FT_UInt idx ) { - if ( (FT_UInt)idx >= mask->num_bits ) + if ( idx >= mask->num_bits ) return 0; return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) ); } - /* clear a given bit */ - static void - ps_mask_clear_bit( PS_Mask mask, - FT_UInt idx ) - { - FT_Byte* p; - - - if ( idx >= mask->num_bits ) - return; - - p = mask->bytes + ( idx >> 3 ); - p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) ); - } - - /* set a given bit, possibly grow the mask */ static FT_Error ps_mask_set_bit( PS_Mask mask, @@ -269,6 +249,10 @@ mask = table->masks + count - 1; mask->num_bits = 0; mask->end_point = 0; + /* reused mask must be cleared */ + if ( mask->max_bits ) + FT_MEM_ZERO( mask->bytes, mask->max_bits >> 3 ); + table->num_masks = count; Exit: @@ -426,7 +410,7 @@ PS_Mask mask2 = table->masks + index2; FT_UInt count1 = mask1->num_bits; FT_UInt count2 = mask2->num_bits; - FT_Int delta; + FT_UInt delta; if ( count2 > 0 ) @@ -437,15 +421,14 @@ /* if "count2" is greater than "count1", we need to grow the */ - /* first bitset, and clear the highest bits */ + /* first bitset */ if ( count2 > count1 ) { error = ps_mask_ensure( mask1, count2, memory ); if ( error ) goto Exit; - for ( pos = count1; pos < count2; pos++ ) - ps_mask_clear_bit( mask1, pos ); + mask1->num_bits = count2; } /* merge (unite) the bitsets */ @@ -467,7 +450,7 @@ mask2->end_point = 0; /* number of masks to move */ - delta = (FT_Int)( table->num_masks - 1 - index2 ); + delta = table->num_masks - 1 - index2; if ( delta > 0 ) { /* move to end of table for reuse */ @@ -476,7 +459,7 @@ ft_memmove( mask2, mask2 + 1, - (FT_UInt)delta * sizeof ( PS_MaskRec ) ); + delta * sizeof ( PS_MaskRec ) ); mask2[delta] = dummy; } @@ -499,23 +482,18 @@ ps_mask_table_merge_all( PS_Mask_Table table, FT_Memory memory ) { - FT_Int index1, index2; + FT_UInt index1, index2; FT_Error error = FT_Err_Ok; - /* both loops go down to 0, thus FT_Int for index1 and index2 */ - for ( index1 = (FT_Int)table->num_masks - 1; index1 > 0; index1-- ) + /* the loops stop when unsigned indices wrap around after 0 */ + for ( index1 = table->num_masks - 1; index1 < table->num_masks; index1-- ) { - for ( index2 = index1 - 1; index2 >= 0; index2-- ) + for ( index2 = index1 - 1; index2 < index1; index2-- ) { - if ( ps_mask_table_test_intersect( table, - (FT_UInt)index1, - (FT_UInt)index2 ) ) + if ( ps_mask_table_test_intersect( table, index1, index2 ) ) { - error = ps_mask_table_merge( table, - (FT_UInt)index2, - (FT_UInt)index1, - memory ); + error = ps_mask_table_merge( table, index2, index1, memory ); if ( error ) goto Exit; @@ -652,7 +630,7 @@ FT_Int pos, FT_Int len, FT_Memory memory, - FT_Int *aindex ) + FT_UInt *aindex ) { FT_Error error = FT_Err_Ok; FT_UInt flags = 0; @@ -670,9 +648,6 @@ len = 0; } - if ( aindex ) - *aindex = -1; - /* now, lookup stem in the current hints table */ { PS_Mask mask; @@ -709,7 +684,7 @@ goto Exit; if ( aindex ) - *aindex = (FT_Int)idx; + *aindex = idx; } Exit: @@ -720,9 +695,9 @@ /* add a "hstem3/vstem3" counter to our dimension table */ static FT_Error ps_dimension_add_counter( PS_Dimension dim, - FT_Int hint1, - FT_Int hint2, - FT_Int hint3, + FT_UInt hint1, + FT_UInt hint2, + FT_UInt hint3, FT_Memory memory ) { FT_Error error = FT_Err_Ok; @@ -749,26 +724,17 @@ } /* now, set the bits for our hints in the counter mask */ - if ( hint1 >= 0 ) - { - error = ps_mask_set_bit( counter, (FT_UInt)hint1, memory ); - if ( error ) - goto Exit; - } + error = ps_mask_set_bit( counter, hint1, memory ); + if ( error ) + goto Exit; - if ( hint2 >= 0 ) - { - error = ps_mask_set_bit( counter, (FT_UInt)hint2, memory ); - if ( error ) - goto Exit; - } + error = ps_mask_set_bit( counter, hint2, memory ); + if ( error ) + goto Exit; - if ( hint3 >= 0 ) - { - error = ps_mask_set_bit( counter, (FT_UInt)hint3, memory ); - if ( error ) - goto Exit; - } + error = ps_mask_set_bit( counter, hint3, memory ); + if ( error ) + goto Exit; Exit: return error; @@ -897,7 +863,7 @@ PS_Dimension dim; FT_Memory memory = hints->memory; FT_Int count; - FT_Int idx[3]; + FT_UInt idx[3]; /* limit "dimension" to 0..1 */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Postscript (Type1/Type2) hints recorder (specification). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * psnames module implementation (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -155,31 +155,30 @@ /* Look for a non-initial dot in the glyph name in order to */ /* find variants like `A.swash', `e.final', etc. */ { - const char* p = glyph_name; - const char* dot = NULL; + FT_UInt32 value = 0; + const char* p = glyph_name; + + for ( ; *p && *p != '.'; p++ ) + ; - for ( ; *p; p++ ) + /* now look up the glyph in the Adobe Glyph List; */ + /* `.notdef', `.null' and the empty name are short cut */ + if ( p > glyph_name ) { - if ( *p == '.' && p > glyph_name ) - { - dot = p; - break; - } + value = (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p ); + + if ( *p == '.' ) + value |= (FT_UInt32)VARIANT_BIT; } - /* now look up the glyph in the Adobe Glyph List */ - if ( !dot ) - return (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p ); - else - return (FT_UInt32)( ft_get_adobe_glyph_index( glyph_name, dot ) | - VARIANT_BIT ); + return value; } } /* ft_qsort callback to sort the unicode map */ - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_uni_maps( const void* a, const void* b ) { @@ -326,9 +325,8 @@ /* we first allocate the table */ table->num_maps = 0; - table->maps = NULL; - if ( !FT_NEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) ) + if ( !FT_QNEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) ) { FT_UInt n; FT_UInt count; @@ -343,7 +341,7 @@ const char* gname = get_glyph_name( glyph_data, n ); - if ( gname ) + if ( gname && *gname ) { ps_check_extra_glyph_name( gname, n, extra_glyphs, extra_glyph_list_states ); @@ -391,9 +389,9 @@ /* Reallocate if the number of used entries is much smaller. */ if ( count < num_glyphs / 2 ) { - (void)FT_RENEW_ARRAY( table->maps, - num_glyphs + EXTRA_GLYPH_LIST_SIZE, - count ); + FT_MEM_QRENEW_ARRAY( table->maps, + num_glyphs + EXTRA_GLYPH_LIST_SIZE, + count ); error = FT_Err_Ok; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level psnames module interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PS names module error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PostScript glyph names. * - * Copyright (C) 2005-2020 by + * Copyright (C) 2005-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Miscellaneous macros for stand-alone rasterizer (specification * only). * - * Copyright (C) 2005-2020 by + * Copyright (C) 2005-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -47,11 +47,8 @@ typedef signed long FT_F26Dot6; typedef int FT_Error; -#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ - ( ( (FT_ULong)_x1 << 24 ) | \ - ( (FT_ULong)_x2 << 16 ) | \ - ( (FT_ULong)_x3 << 8 ) | \ - (FT_ULong)_x4 ) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(FT_Byte)(var) /* from include/freetype/ftsystem.h */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -149,9 +149,6 @@ /*************************************************************************/ /*************************************************************************/ - /* define DEBUG_RASTER if you want to compile a debugging version */ -/* #define DEBUG_RASTER */ - /*************************************************************************/ /*************************************************************************/ @@ -200,12 +197,13 @@ #define FT_THROW( e ) FT_ERR_CAT( Raster_Err_, e ) #endif -#define Raster_Err_None 0 -#define Raster_Err_Not_Ini -1 -#define Raster_Err_Overflow -2 -#define Raster_Err_Neg_Height -3 -#define Raster_Err_Invalid -4 -#define Raster_Err_Unsupported -5 +#define Raster_Err_Ok 0 +#define Raster_Err_Invalid_Outline -1 +#define Raster_Err_Cannot_Render_Glyph -2 +#define Raster_Err_Invalid_Argument -3 +#define Raster_Err_Raster_Overflow -4 +#define Raster_Err_Raster_Uninitialized -5 +#define Raster_Err_Raster_Negative_Height -6 #define ft_memset memset @@ -230,13 +228,6 @@ #include "rasterrs.h" -#define Raster_Err_None FT_Err_Ok -#define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized -#define Raster_Err_Overflow Raster_Err_Raster_Overflow -#define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height -#define Raster_Err_Invalid Raster_Err_Invalid_Outline -#define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph - #endif /* !STANDALONE_ */ @@ -375,16 +366,6 @@ typedef PProfile* PProfileList; - /* Simple record used to implement a stack of bands, required */ - /* by the sub-banding mechanism */ - typedef struct black_TBand_ - { - Short y_min; /* band's minimum */ - Short y_max; /* band's maximum */ - - } black_TBand; - - #define AlignProfileSize \ ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( Long ) ) @@ -426,8 +407,8 @@ /* prototypes used for sweep function dispatch */ typedef void - Function_Sweep_Init( RAS_ARGS Short* min, - Short* max ); + Function_Sweep_Init( RAS_ARGS Short min, + Short max ); typedef void Function_Sweep_Span( RAS_ARGS Short y, @@ -492,10 +473,11 @@ Int numTurns; /* number of Y-turns in outline */ - TPoint* arc; /* current Bezier arc pointer */ + Byte dropOutControl; /* current drop_out control method */ UShort bWidth; /* target bitmap width */ PByte bOrigin; /* target bitmap bottom-left origin */ + PByte bLine; /* target bitmap current line */ Long lastX, lastY; Long minY, maxY; @@ -517,9 +499,6 @@ FT_Bitmap target; /* description of target bit/pixmap */ FT_Outline outline; - Long traceOfs; /* current offset in target bitmap */ - Short traceIncr; /* sweep's increment in target bitmap */ - /* dispatch variables */ Function_Sweep_Init* Proc_Sweep_Init; @@ -527,18 +506,6 @@ Function_Sweep_Span* Proc_Sweep_Drop; Function_Sweep_Step* Proc_Sweep_Step; - Byte dropOutControl; /* current drop_out control method */ - - Bool second_pass; /* indicates whether a horizontal pass */ - /* should be performed to control */ - /* drop-out accurately when calling */ - /* Render_Glyph. */ - - TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ - - black_TBand band_stack[16]; /* band stack used for sub-banding */ - Int band_top; /* band stack top */ - }; @@ -660,7 +627,7 @@ if ( ras.top >= ras.maxBuff ) { - ras.error = FT_THROW( Overflow ); + ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } @@ -689,7 +656,7 @@ default: FT_ERROR(( "New_Profile: invalid profile direction\n" )); - ras.error = FT_THROW( Invalid ); + ras.error = FT_THROW( Invalid_Outline ); return FAILURE; } @@ -731,7 +698,7 @@ if ( h < 0 ) { FT_ERROR(( "End_Profile: negative height encountered\n" )); - ras.error = FT_THROW( Neg_Height ); + ras.error = FT_THROW( Raster_Negative_Height ); return FAILURE; } @@ -767,7 +734,7 @@ if ( ras.top >= ras.maxBuff ) { FT_TRACE1(( "overflow in End_Profile\n" )); - ras.error = FT_THROW( Overflow ); + ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } @@ -822,7 +789,7 @@ ras.maxBuff--; if ( ras.maxBuff <= ras.top ) { - ras.error = FT_THROW( Overflow ); + ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } ras.numTurns++; @@ -1086,7 +1053,7 @@ size = e2 - e1 + 1; if ( ras.top + size >= ras.maxBuff ) { - ras.error = FT_THROW( Overflow ); + ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } @@ -1209,6 +1176,7 @@ */ static Bool Bezier_Up( RAS_ARGS Int degree, + TPoint* arc, TSplitter splitter, Long miny, Long maxy ) @@ -1216,13 +1184,11 @@ Long y1, y2, e, e2, e0; Short f1; - TPoint* arc; TPoint* start_arc; PLong top; - arc = ras.arc; y1 = arc[degree].y; y2 = arc[0].y; top = ras.top; @@ -1271,7 +1237,7 @@ if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) { ras.top = top; - ras.error = FT_THROW( Overflow ); + ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } @@ -1314,7 +1280,6 @@ Fin: ras.top = top; - ras.arc -= degree; return SUCCESS; } @@ -1346,11 +1311,11 @@ */ static Bool Bezier_Down( RAS_ARGS Int degree, + TPoint* arc, TSplitter splitter, Long miny, Long maxy ) { - TPoint* arc = ras.arc; Bool result, fresh; @@ -1362,7 +1327,7 @@ fresh = ras.fresh; - result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); + result = Bezier_Up( RAS_VARS degree, arc, splitter, -maxy, -miny ); if ( fresh && !ras.fresh ) ras.cProfile->start = -ras.cProfile->start; @@ -1503,22 +1468,24 @@ { Long y1, y2, y3, x3, ymin, ymax; TStates state_bez; + TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */ + TPoint* arc; /* current Bezier arc pointer */ - ras.arc = ras.arcs; - ras.arc[2].x = ras.lastX; - ras.arc[2].y = ras.lastY; - ras.arc[1].x = cx; - ras.arc[1].y = cy; - ras.arc[0].x = x; - ras.arc[0].y = y; + arc = arcs; + arc[2].x = ras.lastX; + arc[2].y = ras.lastY; + arc[1].x = cx; + arc[1].y = cy; + arc[0].x = x; + arc[0].y = y; do { - y1 = ras.arc[2].y; - y2 = ras.arc[1].y; - y3 = ras.arc[0].y; - x3 = ras.arc[0].x; + y1 = arc[2].y; + y2 = arc[1].y; + y3 = arc[0].y; + x3 = arc[0].x; /* first, categorize the Bezier arc */ @@ -1536,13 +1503,13 @@ if ( y2 < ymin || y2 > ymax ) { /* this arc has no given direction, split it! */ - Split_Conic( ras.arc ); - ras.arc += 2; + Split_Conic( arc ); + arc += 2; } else if ( y1 == y3 ) { /* this arc is flat, ignore it and pop it from the Bezier stack */ - ras.arc -= 2; + arc -= 2; } else { @@ -1569,15 +1536,18 @@ /* now call the appropriate routine */ if ( state_bez == Ascending_State ) { - if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + if ( Bezier_Up( RAS_VARS 2, arc, Split_Conic, + ras.minY, ras.maxY ) ) goto Fail; } else - if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + if ( Bezier_Down( RAS_VARS 2, arc, Split_Conic, + ras.minY, ras.maxY ) ) goto Fail; + arc -= 2; } - } while ( ras.arc >= ras.arcs ); + } while ( arc >= arcs ); ras.lastX = x3; ras.lastY = y3; @@ -1632,25 +1602,27 @@ { Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; TStates state_bez; + TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ + TPoint* arc; /* current Bezier arc pointer */ - ras.arc = ras.arcs; - ras.arc[3].x = ras.lastX; - ras.arc[3].y = ras.lastY; - ras.arc[2].x = cx1; - ras.arc[2].y = cy1; - ras.arc[1].x = cx2; - ras.arc[1].y = cy2; - ras.arc[0].x = x; - ras.arc[0].y = y; + arc = arcs; + arc[3].x = ras.lastX; + arc[3].y = ras.lastY; + arc[2].x = cx1; + arc[2].y = cy1; + arc[1].x = cx2; + arc[1].y = cy2; + arc[0].x = x; + arc[0].y = y; do { - y1 = ras.arc[3].y; - y2 = ras.arc[2].y; - y3 = ras.arc[1].y; - y4 = ras.arc[0].y; - x4 = ras.arc[0].x; + y1 = arc[3].y; + y2 = arc[2].y; + y3 = arc[1].y; + y4 = arc[0].y; + x4 = arc[0].x; /* first, categorize the Bezier arc */ @@ -1679,13 +1651,13 @@ if ( ymin2 < ymin1 || ymax2 > ymax1 ) { /* this arc has no given direction, split it! */ - Split_Cubic( ras.arc ); - ras.arc += 3; + Split_Cubic( arc ); + arc += 3; } else if ( y1 == y4 ) { /* this arc is flat, ignore it and pop it from the Bezier stack */ - ras.arc -= 3; + arc -= 3; } else { @@ -1711,15 +1683,18 @@ /* compute intersections */ if ( state_bez == Ascending_State ) { - if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + if ( Bezier_Up( RAS_VARS 3, arc, Split_Cubic, + ras.minY, ras.maxY ) ) goto Fail; } else - if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + if ( Bezier_Down( RAS_VARS 3, arc, Split_Cubic, + ras.minY, ras.maxY ) ) goto Fail; + arc -= 3; } - } while ( ras.arc >= ras.arcs ); + } while ( arc >= arcs ); ras.lastX = x4; ras.lastY = y4; @@ -1967,7 +1942,7 @@ return SUCCESS; Invalid_Outline: - ras.error = FT_THROW( Invalid ); + ras.error = FT_THROW( Invalid_Outline ); Fail: return FAILURE; @@ -2120,8 +2095,8 @@ * Removes an old profile from a linked list. */ static void - DelOld( PProfileList list, - PProfile profile ) + DelOld( PProfileList list, + const PProfile profile ) { PProfile *old, current; @@ -2214,16 +2189,13 @@ */ static void - Vertical_Sweep_Init( RAS_ARGS Short* min, - Short* max ) + Vertical_Sweep_Init( RAS_ARGS Short min, + Short max ) { - Long pitch = ras.target.pitch; - FT_UNUSED( max ); - ras.traceIncr = (Short)-pitch; - ras.traceOfs = -*min * pitch; + ras.bLine = ras.bOrigin - min * ras.target.pitch; } @@ -2234,8 +2206,7 @@ PProfile left, PProfile right ) { - Long e1, e2; - Byte* target; + Long e1, e2; Int dropOutControl = left->flags & 7; @@ -2268,6 +2239,8 @@ if ( e2 >= 0 && e1 < ras.bWidth ) { + Byte* target; + Int c1, c2; Byte f1, f2; @@ -2285,7 +2258,7 @@ f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); - target = ras.bOrigin + ras.traceOfs + c1; + target = ras.bLine + c1; c2 -= c1; if ( c2 > 0 ) @@ -2437,8 +2410,8 @@ c1 = (Short)( e1 >> 3 ); f1 = (Short)( e1 & 7 ); - if ( e1 >= 0 && e1 < ras.bWidth && - ras.bOrigin[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) + if ( e1 >= 0 && e1 < ras.bWidth && + ras.bLine[c1] & ( 0x80 >> f1 ) ) goto Exit; } else @@ -2454,7 +2427,7 @@ c1 = (Short)( e1 >> 3 ); f1 = (Short)( e1 & 7 ); - ras.bOrigin[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); + ras.bLine[c1] |= (char)( 0x80 >> f1 ); } Exit: @@ -2465,7 +2438,7 @@ static void Vertical_Sweep_Step( RAS_ARG ) { - ras.traceOfs += ras.traceIncr; + ras.bLine -= ras.target.pitch; } @@ -2479,8 +2452,8 @@ */ static void - Horizontal_Sweep_Init( RAS_ARGS Short* min, - Short* max ) + Horizontal_Sweep_Init( RAS_ARGS Short min, + Short max ) { /* nothing, really */ FT_UNUSED_RASTER; @@ -2744,13 +2717,13 @@ /* check the Y-turns */ if ( ras.numTurns == 0 ) { - ras.error = FT_THROW( Invalid ); + ras.error = FT_THROW( Invalid_Outline ); return FAILURE; } /* now initialize the sweep */ - ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); + ras.Proc_Sweep_Init( RAS_VARS min_Y, max_Y ); /* then compute the distance of each profile from min_Y */ @@ -2977,11 +2950,11 @@ FT_Outline_Get_CBox( const FT_Outline* outline, FT_BBox *acbox ) { - Long xMin, yMin, xMax, yMax; - - if ( outline && acbox ) { + Long xMin, yMin, xMax, yMax; + + if ( outline->n_points == 0 ) { xMin = 0; @@ -3039,63 +3012,54 @@ * Renderer error code. */ static int - Render_Single_Pass( RAS_ARGS Bool flipped ) + Render_Single_Pass( RAS_ARGS Bool flipped, + Int y_min, + Int y_max ) { - Short i, j, k; + Int y_mid; + Int band_top = 0; + Int band_stack[32]; /* enough to bisect 32-bit int bands */ - while ( ras.band_top >= 0 ) + while ( 1 ) { - ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; - ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; + ras.minY = (Long)y_min * ras.precision; + ras.maxY = (Long)y_max * ras.precision; ras.top = ras.buff; - ras.error = Raster_Err_None; + ras.error = Raster_Err_Ok; if ( Convert_Glyph( RAS_VARS flipped ) ) { - if ( ras.error != Raster_Err_Overflow ) - return FAILURE; - - ras.error = Raster_Err_None; + if ( ras.error != Raster_Err_Raster_Overflow ) + return ras.error; /* sub-banding */ -#ifdef DEBUG_RASTER - ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); -#endif + if ( y_min == y_max ) + return ras.error; /* still Raster_Overflow */ - i = ras.band_stack[ras.band_top].y_min; - j = ras.band_stack[ras.band_top].y_max; + y_mid = ( y_min + y_max ) >> 1; - k = (Short)( ( i + j ) / 2 ); - - if ( ras.band_top >= 7 || k < i ) - { - ras.band_top = 0; - ras.error = FT_THROW( Invalid ); - - return ras.error; - } - - ras.band_stack[ras.band_top + 1].y_min = k; - ras.band_stack[ras.band_top + 1].y_max = j; - - ras.band_stack[ras.band_top].y_max = (Short)( k - 1 ); - - ras.band_top++; + band_stack[band_top++] = y_min; + y_min = y_mid + 1; } else { if ( ras.fProfile ) if ( Draw_Sweep( RAS_VAR ) ) return ras.error; - ras.band_top--; + + if ( --band_top < 0 ) + break; + + y_max = y_min - 1; + y_min = band_stack[band_top]; } } - return SUCCESS; + return Raster_Err_Ok; } @@ -3132,9 +3096,6 @@ ras.dropOutControl += 1; } - ras.second_pass = (Bool)( !( ras.outline.flags & - FT_OUTLINE_SINGLE_PASS ) ); - /* Vertical Sweep */ FT_TRACE7(( "Vertical pass (ftraster)\n" )); @@ -3143,21 +3104,18 @@ ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; ras.Proc_Sweep_Step = Vertical_Sweep_Step; - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = (Short)( ras.target.rows - 1 ); - ras.bWidth = (UShort)ras.target.width; ras.bOrigin = (Byte*)ras.target.buffer; if ( ras.target.pitch > 0 ) ras.bOrigin += (Long)( ras.target.rows - 1 ) * ras.target.pitch; - if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) + error = Render_Single_Pass( RAS_VARS 0, 0, (Int)ras.target.rows - 1 ); + if ( error ) return error; /* Horizontal Sweep */ - if ( ras.second_pass && ras.dropOutControl != 2 ) + if ( !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ) ) { FT_TRACE7(( "Horizontal pass (ftraster)\n" )); @@ -3166,22 +3124,12 @@ ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; ras.Proc_Sweep_Step = Horizontal_Sweep_Step; - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = (Short)( ras.target.width - 1 ); - - if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 ) + error = Render_Single_Pass( RAS_VARS 1, 0, (Int)ras.target.width - 1 ); + if ( error ) return error; } - return Raster_Err_None; - } - - - static void - ft_black_init( black_PRaster raster ) - { - FT_UNUSED( raster ); + return Raster_Err_Ok; } @@ -3202,7 +3150,6 @@ *araster = (FT_Raster)&the_raster; FT_ZERO( &the_raster ); - ft_black_init( &the_raster ); return 0; } @@ -3227,14 +3174,10 @@ black_PRaster raster = NULL; - *araster = 0; if ( !FT_NEW( raster ) ) - { raster->memory = memory; - ft_black_init( raster ); - *araster = raster; - } + *araster = raster; return error; } @@ -3292,38 +3235,36 @@ if ( !raster ) - return FT_THROW( Not_Ini ); + return FT_THROW( Raster_Uninitialized ); if ( !outline ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ if ( outline->n_points == 0 || outline->n_contours <= 0 ) - return Raster_Err_None; + return Raster_Err_Ok; if ( !outline->contours || !outline->points ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Outline ); if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Outline ); /* this version of the raster does not support direct rendering, sorry */ - if ( params->flags & FT_RASTER_FLAG_DIRECT ) - return FT_THROW( Unsupported ); - - if ( params->flags & FT_RASTER_FLAG_AA ) - return FT_THROW( Unsupported ); + if ( params->flags & FT_RASTER_FLAG_DIRECT || + params->flags & FT_RASTER_FLAG_AA ) + return FT_THROW( Cannot_Render_Glyph ); if ( !target_map ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Argument ); /* nothing to do */ if ( !target_map->width || !target_map->rows ) - return Raster_Err_None; + return Raster_Err_Ok; if ( !target_map->buffer ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Argument ); ras.outline = *outline; ras.target = *target_map; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * monochrome renderer error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * @@ -270,7 +270,10 @@ int bitdepth, color_type, interlace; FT_Int i; - png_byte* *rows = NULL; /* pacify compiler */ + + /* `rows` gets modified within a 'setjmp' scope; */ + /* we thus need the `volatile` keyword. */ + png_byte* *volatile rows = NULL; if ( x_offset < 0 || @@ -427,7 +430,7 @@ goto DestroyExit; } - if ( FT_NEW_ARRAY( rows, imgHeight ) ) + if ( FT_QNEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; @@ -438,11 +441,11 @@ png_read_image( png, rows ); - FT_FREE( rows ); - png_read_end( png, info ); DestroyExit: + /* even if reading fails with longjmp, rows must be freed */ + FT_FREE( rows ); png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2022 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -36,6 +36,10 @@ #include "ttcpal.h" #endif +#ifdef FT_CONFIG_OPTION_SVG +#include "ttsvg.h" +#endif + #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES #include "ttpost.h" #endif @@ -491,17 +495,15 @@ char_type_func char_type, FT_Bool report_invalid_characters ) { - FT_Error error = FT_Err_Ok; + FT_Error error; char* result = NULL; FT_String* r; FT_Char* p; FT_UInt len; - FT_UNUSED( error ); - - if ( FT_ALLOC( result, entry->stringLength / 2 + 1 ) ) + if ( FT_QALLOC( result, entry->stringLength / 2 + 1 ) ) return NULL; if ( FT_STREAM_SEEK( entry->stringOffset ) || @@ -550,17 +552,15 @@ char_type_func char_type, FT_Bool report_invalid_characters ) { - FT_Error error = FT_Err_Ok; + FT_Error error; char* result = NULL; FT_String* r; FT_Char* p; FT_UInt len; - FT_UNUSED( error ); - - if ( FT_ALLOC( result, entry->stringLength + 1 ) ) + if ( FT_QALLOC( result, entry->stringLength + 1 ) ) return NULL; if ( FT_STREAM_SEEK( entry->stringOffset ) || @@ -868,8 +868,8 @@ result[len] = '\0'; FT_TRACE0(( "sfnt_get_var_ps_name:" - " Shortening variation PS name prefix\n" - " " + " Shortening variation PS name prefix\n" )); + FT_TRACE0(( " " " to %d characters\n", len )); } @@ -920,16 +920,16 @@ if ( !subfamily_name ) { FT_TRACE1(( "sfnt_get_var_ps_name:" - " can't construct named instance PS name;\n" - " " + " can't construct named instance PS name;\n" )); + FT_TRACE1(( " " " trying to construct normal instance PS name\n" )); goto construct_instance_name; } /* after the prefix we have character `-' followed by the */ /* subfamily name (using only characters a-z, A-Z, and 0-9) */ - if ( FT_ALLOC( result, face->var_postscript_prefix_len + - 1 + ft_strlen( subfamily_name ) + 1 ) ) + if ( FT_QALLOC( result, face->var_postscript_prefix_len + + 1 + ft_strlen( subfamily_name ) + 1 ) ) return NULL; ft_strcpy( result, face->var_postscript_prefix ); @@ -957,9 +957,9 @@ construct_instance_name: axis = mm_var->axis; - if ( FT_ALLOC( result, - face->var_postscript_prefix_len + - num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) ) + if ( FT_QALLOC( result, + face->var_postscript_prefix_len + + num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) ) return NULL; p = result; @@ -993,6 +993,7 @@ if ( t != ' ' && ft_isalnum( t ) ) *p++ = t; } + *p++ = '\0'; } check_length: @@ -1213,6 +1214,14 @@ #define PUT_COLOR_LAYERS( a ) NULL #endif +#ifdef FT_CONFIG_OPTION_SVG +#define PUT_SVG_SUPPORT( a ) a +#else +#define PUT_SVG_SUPPORT( a ) NULL +#endif + +#define PUT_COLOR_LAYERS_V1( a ) PUT_COLOR_LAYERS( a ) + #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES #define PUT_PS_NAMES( a ) a #else @@ -1271,9 +1280,9 @@ /* TT_Free_Table_Func free_eblc */ PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), - /* TT_Set_SBit_Strike_Func set_sbit_strike */ + /* TT_Set_SBit_Strike_Func set_sbit_strike */ PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), - /* TT_Load_Strike_Metrics_Func load_strike_metrics */ + /* TT_Load_Strike_Metrics_Func load_strike_metrics */ PUT_COLOR_LAYERS( tt_face_load_cpal ), /* TT_Load_Table_Func load_cpal */ @@ -1287,13 +1296,32 @@ /* TT_Set_Palette_Func set_palette */ PUT_COLOR_LAYERS( tt_face_get_colr_layer ), /* TT_Get_Colr_Layer_Func get_colr_layer */ + + PUT_COLOR_LAYERS_V1( tt_face_get_colr_glyph_paint ), + /* TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_color_glyph_clipbox ), + /* TT_Get_Color_Glyph_ClipBox_Func get_clipbox */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint_layers ), + /* TT_Get_Paint_Layers_Func get_paint_layers */ + PUT_COLOR_LAYERS_V1( tt_face_get_colorline_stops ), + /* TT_Get_Paint get_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint ), + /* TT_Get_Colorline_Stops_Func get_colorline_stops */ + PUT_COLOR_LAYERS( tt_face_colr_blend_layer ), /* TT_Blend_Colr_Func colr_blend */ tt_face_get_metrics, /* TT_Get_Metrics_Func get_metrics */ tt_face_get_name, /* TT_Get_Name_Func get_name */ - sfnt_get_name_id /* TT_Get_Name_ID_Func get_name_id */ + sfnt_get_name_id, /* TT_Get_Name_ID_Func get_name_id */ + + PUT_SVG_SUPPORT( tt_face_load_svg ), + /* TT_Load_Table_Func load_svg */ + PUT_SVG_SUPPORT( tt_face_free_svg ), + /* TT_Free_Table_Func free_svg */ + PUT_SVG_SUPPORT( tt_face_load_svg_doc ) + /* TT_Load_Svg_Doc_Func load_svg_doc */ ) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * SFNT error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * SFNT object management (base). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -65,7 +65,7 @@ len = (FT_UInt)entry->stringLength / 2; - if ( FT_NEW_ARRAY( string, len + 1 ) ) + if ( FT_QNEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) @@ -100,7 +100,7 @@ len = (FT_UInt)entry->stringLength; - if ( FT_NEW_ARRAY( string, len + 1 ) ) + if ( FT_QNEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) @@ -360,17 +360,27 @@ FT_FRAME_END }; +#ifndef FT_CONFIG_OPTION_USE_BROTLI + FT_UNUSED( face_instance_index ); + FT_UNUSED( woff2_num_faces ); +#endif + face->ttc_header.tag = 0; face->ttc_header.version = 0; face->ttc_header.count = 0; +#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ + defined( FT_CONFIG_OPTION_USE_BROTLI ) retry: +#endif + offset = FT_STREAM_POS(); if ( FT_READ_ULONG( tag ) ) return error; +#ifdef FT_CONFIG_OPTION_USE_ZLIB if ( tag == TTAG_wOFF ) { FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" )); @@ -386,7 +396,9 @@ stream = face->root.stream; goto retry; } +#endif +#ifdef FT_CONFIG_OPTION_USE_BROTLI if ( tag == TTAG_wOF2 ) { FT_TRACE2(( "sfnt_open_font: file is a WOFF2; synthesizing SFNT\n" )); @@ -405,6 +417,7 @@ stream = face->root.stream; goto retry; } +#endif if ( tag != 0x00010000UL && tag != TTAG_ttcf && @@ -446,7 +459,7 @@ return FT_THROW( Array_Too_Large ); /* now read the offsets of each font in the file */ - if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) + if ( FT_QNEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) return error; if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) @@ -464,7 +477,7 @@ face->ttc_header.version = 1 << 16; face->ttc_header.count = 1; - if ( FT_NEW( face->ttc_header.offsets ) ) + if ( FT_QNEW( face->ttc_header.offsets ) ) return error; face->ttc_header.offsets[0] = offset; @@ -553,7 +566,7 @@ face_index = FT_ABS( face_instance_index ) & 0xFFFF; /* value -(N+1) requests information on index N */ - if ( face_instance_index < 0 ) + if ( face_instance_index < 0 && face_index > 0 ) face_index--; if ( face_index >= face->ttc_header.count ) @@ -643,8 +656,8 @@ */ if ( ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) && - !( FT_ALLOC( default_values, num_axes * 4 ) || - FT_ALLOC( instance_values, num_axes * 4 ) ) ) + !( FT_QALLOC( default_values, num_axes * 4 ) || + FT_QALLOC( instance_values, num_axes * 4 ) ) ) { /* the current stream position is 16 bytes after the table start */ FT_ULong array_start = FT_STREAM_POS() - 16 + offset; @@ -771,17 +784,23 @@ FT_Int num_params, FT_Parameter* params ) { - FT_Error error; + FT_Error error; #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES - FT_Error psnames_error; + FT_Error psnames_error; #endif - FT_Bool has_outline; - FT_Bool is_apple_sbit; - FT_Bool is_apple_sbix; - FT_Bool has_CBLC; - FT_Bool has_CBDT; - FT_Bool ignore_typographic_family = FALSE; - FT_Bool ignore_typographic_subfamily = FALSE; + + FT_Bool has_outline; + FT_Bool is_apple_sbit; + + FT_Bool has_CBLC; + FT_Bool has_CBDT; + FT_Bool has_EBLC; + FT_Bool has_bloc; + FT_Bool has_sbix; + + FT_Bool ignore_typographic_family = FALSE; + FT_Bool ignore_typographic_subfamily = FALSE; + FT_Bool ignore_sbix = FALSE; SFNT_Service sfnt = (SFNT_Service)face->sfnt; @@ -800,6 +819,8 @@ ignore_typographic_family = TRUE; else if ( params[i].tag == FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY ) ignore_typographic_subfamily = TRUE; + else if ( params[i].tag == FT_PARAM_TAG_IGNORE_SBIX ) + ignore_sbix = TRUE; } } @@ -820,7 +841,8 @@ /* it doesn't contain outlines. */ /* */ - FT_TRACE2(( "sfnt_load_face: %p\n\n", (void *)face )); + FT_TRACE2(( "sfnt_load_face: %p\n", (void *)face )); + FT_TRACE2(( "\n" )); /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL @@ -834,14 +856,17 @@ tt_face_lookup_table( face, TTAG_CFF2 ) ); #endif - is_apple_sbit = 0; - is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); + /* check which sbit formats are present */ + has_CBLC = !face->goto_table( face, TTAG_CBLC, stream, 0 ); + has_CBDT = !face->goto_table( face, TTAG_CBDT, stream, 0 ); + has_EBLC = !face->goto_table( face, TTAG_EBLC, stream, 0 ); + has_bloc = !face->goto_table( face, TTAG_bloc, stream, 0 ); + has_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); - /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf' - * outline rendered on top. We don't support that yet, so just ignore - * the 'glyf' outline and advertise it as a bitmap-only font. */ - if ( is_apple_sbix ) - has_outline = FALSE; + is_apple_sbit = FALSE; + + if ( ignore_sbix ) + has_sbix = FALSE; /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ @@ -853,16 +878,13 @@ /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ - if ( !is_apple_sbit || is_apple_sbix ) + if ( !is_apple_sbit || has_sbix ) { LOAD_( head ); if ( error ) goto Exit; } - has_CBLC = !face->goto_table( face, TTAG_CBLC, stream, 0 ); - has_CBDT = !face->goto_table( face, TTAG_CBDT, stream, 0 ); - /* Ignore outlines for CBLC/CBDT fonts. */ if ( has_CBLC || has_CBDT ) has_outline = FALSE; @@ -972,7 +994,11 @@ /* the optional tables */ /* embedded bitmap support */ - if ( sfnt->load_eblc ) + /* TODO: Replace this clumsy check for all possible sbit tables */ + /* with something better (for example, by passing a parameter */ + /* to suppress 'sbix' loading). */ + if ( sfnt->load_eblc && + ( has_CBLC || has_EBLC || has_bloc || has_sbix ) ) LOAD_( eblc ); /* colored glyph support */ @@ -982,6 +1008,10 @@ LOAD_( colr ); } + /* OpenType-SVG glyph support */ + if ( sfnt->load_svg ) + LOAD_( svg ); + /* consider the pclt, kerning, and gasp tables as optional */ LOAD_( pclt ); LOAD_( gasp ); @@ -1040,7 +1070,14 @@ flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ if ( has_outline == TRUE ) - flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + { + /* by default (and for backward compatibility) we handle */ + /* fonts with an 'sbix' table as bitmap-only */ + if ( has_sbix ) + flags |= FT_FACE_FLAG_SBIX; /* with 'sbix' bitmaps */ + else + flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + } /* The sfnt driver only supports bitmap fonts natively, thus we */ /* don't set FT_FACE_FLAG_HINTER. */ @@ -1149,9 +1186,10 @@ } /* synthesize Unicode charmap if one is missing */ - if ( !has_unicode ) + if ( !has_unicode && + root->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) { - FT_CharMapRec cmaprec; + FT_CharMapRec cmaprec; cmaprec.face = root; @@ -1207,7 +1245,7 @@ /* of `FT_Face', we map `available_sizes' indices to strike */ /* indices */ if ( FT_NEW_ARRAY( root->available_sizes, count ) || - FT_NEW_ARRAY( sbit_strike_map, count ) ) + FT_QNEW_ARRAY( sbit_strike_map, count ) ) goto Exit; bsize_idx = 0; @@ -1236,7 +1274,7 @@ } /* reduce array size to the actually used elements */ - (void)FT_RENEW_ARRAY( sbit_strike_map, count, bsize_idx ); + FT_MEM_QRENEW_ARRAY( sbit_strike_map, count, bsize_idx ); /* from now on, all strike indices are mapped */ /* using `sbit_strike_map' */ @@ -1262,7 +1300,8 @@ * * Set up metrics. */ - if ( FT_IS_SCALABLE( root ) ) + if ( FT_IS_SCALABLE( root ) || + FT_HAS_SBIX( root ) ) { /* XXX What about if outline header is missing */ /* (e.g. sfnt wrapped bitmap)? */ @@ -1401,6 +1440,12 @@ sfnt->free_cpal( face ); sfnt->free_colr( face ); } + +#ifdef FT_CONFIG_OPTION_SVG + /* free SVG data */ + if ( sfnt->free_svg ) + sfnt->free_svg( face ); +#endif } #ifdef TT_CONFIG_OPTION_BDF diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * SFNT object management (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * WOFF2 format management (base). * - * Copyright (C) 2019-2020 by + * Copyright (C) 2019-2022 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,8 +26,6 @@ #include -#endif - /************************************************************************** * @@ -86,6 +84,8 @@ #define BBOX_STREAM 5 #define INSTRUCTION_STREAM 6 +#define HAVE_OVERLAP_SIMPLE_BITMAP 0x1 + static void stream_close( FT_Stream stream ) @@ -96,20 +96,19 @@ FT_FREE( stream->base ); stream->size = 0; - stream->base = NULL; stream->close = NULL; } - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_tags( const void* a, const void* b ) { WOFF2_Table table1 = *(WOFF2_Table*)a; WOFF2_Table table2 = *(WOFF2_Table*)b; - FT_ULong tag1 = table1->Tag; - FT_ULong tag2 = table2->Tag; + FT_Tag tag1 = table1->Tag; + FT_Tag tag2 = table2->Tag; if ( tag1 > tag2 ) @@ -316,8 +315,6 @@ const FT_Byte* src, FT_ULong src_size ) { -#ifdef FT_CONFIG_OPTION_USE_BROTLI - /* this cast is only of importance on 32bit systems; */ /* we don't validate it */ FT_Offset uncompressed_size = (FT_Offset)dst_size; @@ -338,20 +335,13 @@ FT_TRACE2(( "woff2_decompress: Brotli stream decompressed.\n" )); return FT_Err_Ok; - -#else /* !FT_CONFIG_OPTION_USE_BROTLI */ - - FT_ERROR(( "woff2_decompress: Brotli support not available.\n" )); - return FT_THROW( Unimplemented_Feature ); - -#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ } static WOFF2_Table find_table( WOFF2_Table* tables, FT_UShort num_tables, - FT_ULong tag ) + FT_Tag tag ) { FT_Int i; @@ -534,6 +524,7 @@ const WOFF2_Point points, FT_UShort n_contours, FT_UShort instruction_len, + FT_Bool have_overlap, FT_Byte* dst, FT_ULong dst_size, FT_ULong* glyph_size ) @@ -561,6 +552,9 @@ FT_Int dy = point.y - last_y; + if ( i == 0 && have_overlap ) + flag |= GLYF_OVERLAP_SIMPLE; + if ( dx == 0 ) flag |= GLYF_THIS_X_IS_SAME; else if ( dx > -256 && dx < 256 ) @@ -790,7 +784,7 @@ goto Fail; loca_buf_size = loca_values_size * offset_size; - if ( FT_NEW_ARRAY( loca_buf, loca_buf_size ) ) + if ( FT_QNEW_ARRAY( loca_buf, loca_buf_size ) ) goto Fail; dst = loca_buf; @@ -845,15 +839,18 @@ FT_UInt num_substreams = 7; + FT_UShort option_flags; FT_UShort num_glyphs; FT_UShort index_format; FT_ULong expected_loca_length; FT_UInt offset; FT_UInt i; FT_ULong points_size; - FT_ULong bitmap_length; FT_ULong glyph_buf_size; FT_ULong bbox_bitmap_offset; + FT_ULong bbox_bitmap_length; + FT_ULong overlap_bitmap_offset = 0; + FT_ULong overlap_bitmap_length = 0; const FT_ULong glyf_start = *out_offset; FT_ULong dest_offset = *out_offset; @@ -869,15 +866,17 @@ if ( FT_NEW_ARRAY( substreams, num_substreams ) ) goto Fail; - if ( FT_STREAM_SKIP( 4 ) ) + if ( FT_STREAM_SKIP( 2 ) ) + goto Fail; + if ( FT_READ_USHORT( option_flags ) ) goto Fail; if ( FT_READ_USHORT( num_glyphs ) ) goto Fail; if ( FT_READ_USHORT( index_format ) ) goto Fail; - FT_TRACE4(( "num_glyphs = %u; index_format = %u\n", - num_glyphs, index_format )); + FT_TRACE4(( "option_flags = %u; num_glyphs = %u; index_format = %u\n", + option_flags, num_glyphs, index_format )); info->num_glyphs = num_glyphs; @@ -890,7 +889,7 @@ if ( info->loca_table->dst_length != expected_loca_length ) goto Fail; - offset = ( 2 + num_substreams ) * 4; + offset = 2 + 2 + 2 + 2 + ( num_substreams * 4 ); if ( offset > info->glyf_table->TransformLength ) goto Fail; @@ -913,6 +912,20 @@ offset += substream_size; } + if ( option_flags & HAVE_OVERLAP_SIMPLE_BITMAP ) + { + /* Size of overlapBitmap = floor((numGlyphs + 7) / 8) */ + overlap_bitmap_length = ( num_glyphs + 7U ) >> 3; + if ( overlap_bitmap_length > info->glyf_table->TransformLength - offset ) + goto Fail; + + overlap_bitmap_offset = pos + offset; + + FT_TRACE5(( " Overlap bitmap: offset = %lu; size = %lu;\n", + overlap_bitmap_offset, overlap_bitmap_length )); + offset += overlap_bitmap_length; + } + if ( FT_NEW_ARRAY( loca_values, num_glyphs + 1 ) ) goto Fail; @@ -920,8 +933,9 @@ bbox_bitmap_offset = substreams[BBOX_STREAM].offset; /* Size of bboxBitmap = 4 * floor((numGlyphs + 31) / 32) */ - bitmap_length = ( ( num_glyphs + 31U ) >> 5 ) << 2; - substreams[BBOX_STREAM].offset += bitmap_length; + bbox_bitmap_length = ( ( num_glyphs + 31U ) >> 5 ) << 2; + /* bboxStreamSize is the combined size of bboxBitmap and bboxStream. */ + substreams[BBOX_STREAM].offset += bbox_bitmap_length; glyph_buf_size = WOFF2_DEFAULT_GLYPH_BUF; if ( FT_NEW_ARRAY( glyph_buf, glyph_buf_size ) ) @@ -1037,8 +1051,11 @@ FT_ULong flag_size; FT_ULong triplet_size; FT_ULong triplet_bytes_used; - FT_Byte* flags_buf = NULL; - FT_Byte* triplet_buf = NULL; + FT_Bool have_overlap = FALSE; + FT_Byte overlap_bitmap; + FT_ULong overlap_offset; + FT_Byte* flags_buf = NULL; + FT_Byte* triplet_buf = NULL; FT_UShort instruction_size; FT_ULong size_needed; FT_Int end_point; @@ -1047,6 +1064,17 @@ FT_Byte* pointer = NULL; + /* Set `have_overlap`. */ + if ( overlap_bitmap_offset ) + { + overlap_offset = overlap_bitmap_offset + ( i >> 3 ); + if ( FT_STREAM_SEEK( overlap_offset ) || + FT_READ_BYTE( overlap_bitmap ) ) + goto Fail; + if ( overlap_bitmap & ( 0x80 >> ( i & 7 ) ) ) + have_overlap = TRUE; + } + if ( FT_NEW_ARRAY( n_points_arr, n_contours ) ) goto Fail; @@ -1167,6 +1195,7 @@ points, n_contours, instruction_size, + have_overlap, glyph_buf, glyph_buf_size, &glyph_size ) ) @@ -1852,11 +1881,10 @@ FT_NEW_ARRAY( indices, woff2.num_tables ) ) goto Exit; - FT_TRACE2(( - "\n" - " tag flags transform origLen transformLen offset\n" - " -----------------------------------------------------------\n" )); - /* " XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX" */ + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag flags transform origLen transformLen offset\n" )); + FT_TRACE2(( " -----------------------------------------------------------\n" )); + /* " XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX" */ for ( nn = 0; nn < woff2.num_tables; nn++ ) { @@ -2098,7 +2126,7 @@ /* Validate requested face index. */ *num_faces = woff2.num_fonts; /* value -(N+1) requests information on index N */ - if ( *face_instance_index < 0 ) + if ( *face_instance_index < 0 && face_index > 0 ) face_index--; if ( face_index >= woff2.num_fonts ) @@ -2119,8 +2147,8 @@ /* Create a temporary array. */ - if ( FT_NEW_ARRAY( temp_indices, - ttc_font->num_tables ) ) + if ( FT_QNEW_ARRAY( temp_indices, + ttc_font->num_tables ) ) goto Exit; FT_TRACE4(( "Storing tables for TTC face index %d.\n", face_index )); @@ -2128,9 +2156,9 @@ temp_indices[nn] = indices[ttc_font->table_indices[nn]]; /* Resize array to required size. */ - if ( FT_RENEW_ARRAY( indices, - woff2.num_tables, - ttc_font->num_tables ) ) + if ( FT_QRENEW_ARRAY( indices, + woff2.num_tables, + ttc_font->num_tables ) ) goto Exit; for ( nn = 0; nn < ttc_font->num_tables; nn++ ) @@ -2170,8 +2198,8 @@ } /* Write sfnt header. */ - if ( FT_ALLOC( sfnt, sfnt_size ) || - FT_NEW( sfnt_stream ) ) + if ( FT_QALLOC( sfnt, sfnt_size ) || + FT_NEW( sfnt_stream ) ) goto Exit; sfnt_header = sfnt; @@ -2209,6 +2237,25 @@ sizeof ( WOFF2_Table ), compare_tags ); + /* reject fonts that have multiple tables with the same tag */ + for ( nn = 1; nn < woff2.num_tables; nn++ ) + { + FT_Tag tag = indices[nn]->Tag; + + + if ( tag == indices[nn - 1]->Tag ) + { + FT_ERROR(( "woff2_open_font:" + " multiple tables with tag `%c%c%c%c'.\n", + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + if ( woff2.uncompressed_size < 1 ) { error = FT_THROW( Invalid_Table ); @@ -2223,8 +2270,8 @@ } /* Allocate memory for uncompressed table data. */ - if ( FT_ALLOC( uncompressed_buf, woff2.uncompressed_size ) || - FT_FRAME_ENTER( woff2.totalCompressedSize ) ) + if ( FT_QALLOC( uncompressed_buf, woff2.uncompressed_size ) || + FT_FRAME_ENTER( woff2.totalCompressedSize ) ) goto Exit; /* Uncompress the stream. */ @@ -2333,5 +2380,12 @@ #undef BBOX_STREAM #undef INSTRUCTION_STREAM +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int _sfwoff2_dummy; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + /* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * WOFFF2 format management (specification). * - * Copyright (C) 2019-2020 by + * Copyright (C) 2019-2022 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,6 +26,7 @@ FT_BEGIN_HEADER +#ifdef FT_CONFIG_OPTION_USE_BROTLI /* Leave the first byte open to store `flag_byte'. */ #define WOFF2_FLAGS_TRANSFORM 1 << 8 @@ -55,6 +56,7 @@ #define GLYF_REPEAT 1 << 3 #define GLYF_THIS_X_IS_SAME 1 << 4 #define GLYF_THIS_Y_IS_SAME 1 << 5 +#define GLYF_OVERLAP_SIMPLE 1 << 6 /* Other constants */ #define CONTOUR_OFFSET_END_POINT 10 @@ -66,6 +68,7 @@ FT_Int* face_index, FT_Long* num_faces ); +#endif /* FT_CONFIG_OPTION_USE_BROTLI */ FT_END_HEADER diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * WOFF format management (base). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -23,6 +23,9 @@ #include +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit @@ -61,12 +64,11 @@ FT_FREE( stream->base ); stream->size = 0; - stream->base = NULL; stream->close = NULL; } - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_offsets( const void* a, const void* b ) { @@ -109,7 +111,7 @@ FT_ULong sfnt_offset; FT_Int nn; - FT_ULong old_tag = 0; + FT_Tag old_tag = 0; static const FT_Frame_Field woff_header_fields[] = { @@ -160,8 +162,8 @@ } /* Don't trust `totalSfntSize' before thorough checks. */ - if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) || - FT_NEW( sfnt_stream ) ) + if ( FT_QALLOC( sfnt, 12 + woff.num_tables * 16UL ) || + FT_NEW( sfnt_stream ) ) goto Exit; sfnt_header = sfnt; @@ -198,9 +200,9 @@ FT_NEW_ARRAY( indices, woff.num_tables ) ) goto Exit; - FT_TRACE2(( "\n" - " tag offset compLen origLen checksum\n" - " -------------------------------------------\n" )); + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset compLen origLen checksum\n" )); + FT_TRACE2(( " -------------------------------------------\n" )); if ( FT_FRAME_ENTER( 20L * woff.num_tables ) ) goto Exit; @@ -360,8 +362,6 @@ } else { -#ifdef FT_CONFIG_OPTION_USE_ZLIB - /* Uncompress with zlib. */ FT_ULong output_len = table->OrigLength; @@ -377,13 +377,6 @@ error = FT_THROW( Invalid_Table ); goto Exit1; } - -#else /* !FT_CONFIG_OPTION_USE_ZLIB */ - - error = FT_THROW( Unimplemented_Feature ); - goto Exit1; - -#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ } FT_FRAME_EXIT(); @@ -433,5 +426,12 @@ #undef WRITE_USHORT #undef WRITE_ULONG +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + /* ANSI C doesn't like empty source files */ + typedef int _sfwoff_dummy; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + /* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * WOFFF format management (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,12 +26,15 @@ FT_BEGIN_HEADER +#ifdef FT_CONFIG_OPTION_USE_ZLIB FT_LOCAL( FT_Error ) woff_open_font( FT_Stream stream, TT_Face face ); +#endif + FT_END_HEADER #endif /* SFWOFF_H_ */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -915,6 +915,16 @@ length = (FT_UInt)( valid->limit - table ); } + + /* it also happens that the `length' field is too small; */ + /* this is easy to correct */ + if ( length < (FT_UInt)( valid->limit - table ) ) + { + if ( valid->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + + length = (FT_UInt)( valid->limit - table ); + } if ( length < 16 ) FT_INVALID_TOO_SHORT; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TT CMAP classes definitions (specification only). * - * Copyright (C) 2009-2020 by + * Copyright (C) 2009-2022 by * Oran Agra and Mickey Gabel. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,8 +4,8 @@ * * TrueType and OpenType colored glyph layer support (body). * - * Copyright (C) 2018-2020 by - * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright (C) 2018-2022 by + * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. * * Originally written by Shao Yu Zhang . * @@ -27,10 +27,12 @@ */ +#include #include #include #include #include +#include #ifdef TT_CONFIG_OPTION_COLOR_LAYERS @@ -39,12 +41,27 @@ /* NOTE: These are the table sizes calculated through the specs. */ -#define BASE_GLYPH_SIZE 6U -#define LAYER_SIZE 4U -#define COLR_HEADER_SIZE 14U +#define BASE_GLYPH_SIZE 6U +#define BASE_GLYPH_PAINT_RECORD_SIZE 6U +#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U +#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U +#define COLOR_STOP_SIZE 6U +#define LAYER_SIZE 4U +#define COLR_HEADER_SIZE 14U - typedef struct BaseGlyphRecord_ + typedef enum FT_PaintFormat_Internal_ + { + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22, + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER = 26, + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30 + + } FT_PaintFormat_Internal; + + + typedef struct BaseGlyphRecord_ { FT_UShort gid; FT_UShort first_layer_index; @@ -53,7 +70,16 @@ } BaseGlyphRecord; - typedef struct Colr_ + typedef struct BaseGlyphV1Record_ + { + FT_UShort gid; + /* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */ + FT_ULong paint_offset; + + } BaseGlyphV1Record; + + + typedef struct Colr_ { FT_UShort version; FT_UShort num_base_glyphs; @@ -62,7 +88,23 @@ FT_Byte* base_glyphs; FT_Byte* layers; - /* The memory which backs up the `COLR' table. */ + FT_ULong num_base_glyphs_v1; + /* Points at beginning of BaseGlyphV1List. */ + FT_Byte* base_glyphs_v1; + + FT_ULong num_layers_v1; + FT_Byte* layers_v1; + + FT_Byte* clip_list; + + /* + * Paint tables start at the minimum of the end of the LayerList and the + * end of the BaseGlyphList. Record this location in a field here for + * safety checks when accessing paint tables. + */ + FT_Byte* paints_start_v1; + + /* The memory that backs up the `COLR' table. */ void* table; FT_ULong table_size; @@ -88,10 +130,14 @@ FT_Byte* table = NULL; FT_Byte* p = NULL; + /* Needed for reading array lengths in referenced tables. */ + FT_Byte* p1 = NULL; Colr* colr = NULL; FT_ULong base_glyph_offset, layer_offset; + FT_ULong base_glyphs_offset_v1, num_base_glyphs_v1; + FT_ULong layer_offset_v1, num_layers_v1, clip_list_offset; FT_ULong table_size; @@ -115,7 +161,7 @@ goto NoColr; colr->version = FT_NEXT_USHORT( p ); - if ( colr->version != 0 ) + if ( colr->version != 0 && colr->version != 1 ) goto InvalidTable; colr->num_base_glyphs = FT_NEXT_USHORT( p ); @@ -135,6 +181,66 @@ if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset ) goto InvalidTable; + if ( colr->version == 1 ) + { + base_glyphs_offset_v1 = FT_NEXT_ULONG( p ); + + if ( base_glyphs_offset_v1 >= table_size ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + base_glyphs_offset_v1 ); + num_base_glyphs_v1 = FT_PEEK_ULONG( p1 ); + + if ( num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE > + table_size - base_glyphs_offset_v1 ) + goto InvalidTable; + + colr->num_base_glyphs_v1 = num_base_glyphs_v1; + colr->base_glyphs_v1 = p1; + + layer_offset_v1 = FT_NEXT_ULONG( p ); + + if ( layer_offset_v1 >= table_size ) + goto InvalidTable; + + if ( layer_offset_v1 ) + { + p1 = (FT_Byte*)( table + layer_offset_v1 ); + num_layers_v1 = FT_PEEK_ULONG( p1 ); + + if ( num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE > + table_size - layer_offset_v1 ) + goto InvalidTable; + + colr->num_layers_v1 = num_layers_v1; + colr->layers_v1 = p1; + + colr->paints_start_v1 = + FT_MIN( colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE, + colr->layers_v1 + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ); + } + else + { + colr->num_layers_v1 = 0; + colr->layers_v1 = 0; + colr->paints_start_v1 = + colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE; + } + + clip_list_offset = FT_NEXT_ULONG( p ); + + if ( clip_list_offset >= table_size ) + goto InvalidTable; + + if ( clip_list_offset ) + colr->clip_list = (FT_Byte*)( table + clip_list_offset ); + else + colr->clip_list = 0; + } + colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset ); colr->layers = (FT_Byte*)( table + layer_offset ); colr->table = table; @@ -174,17 +280,17 @@ static FT_Bool find_base_glyph_record( FT_Byte* base_glyph_begin, - FT_Int num_base_glyph, + FT_UInt num_base_glyph, FT_UInt glyph_id, BaseGlyphRecord* record ) { - FT_Int min = 0; - FT_Int max = num_base_glyph - 1; + FT_UInt min = 0; + FT_UInt max = num_base_glyph; - while ( min <= max ) + while ( min < max ) { - FT_Int mid = min + ( max - min ) / 2; + FT_UInt mid = min + ( max - min ) / 2; FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE; FT_UShort gid = FT_NEXT_USHORT( p ); @@ -193,7 +299,7 @@ if ( gid < glyph_id ) min = mid + 1; else if (gid > glyph_id ) - max = mid - 1; + max = mid; else { record->gid = gid; @@ -265,6 +371,778 @@ } + static FT_Bool + read_color_line( FT_Byte* color_line_p, + FT_ColorLine *colorline ) + { + FT_Byte* p = color_line_p; + FT_PaintExtend paint_extend; + + + paint_extend = (FT_PaintExtend)FT_NEXT_BYTE( p ); + if ( paint_extend > FT_COLR_PAINT_EXTEND_REFLECT ) + return 0; + + colorline->extend = paint_extend; + + colorline->color_stop_iterator.num_color_stops = FT_NEXT_USHORT( p ); + colorline->color_stop_iterator.p = p; + colorline->color_stop_iterator.current_color_stop = 0; + + return 1; + } + + + /* + * Read a paint offset for `FT_Paint*` objects that have them and check + * whether it is within reasonable limits within the font and the COLR + * table. + * + * Return 1 on success, 0 on failure. + */ + static FT_Bool + get_child_table_pointer ( Colr* colr, + FT_Byte* paint_base, + FT_Byte** p, + FT_Byte** child_table_pointer ) + { + FT_UInt32 paint_offset; + FT_Byte* child_table_p; + + + if ( !child_table_pointer ) + return 0; + + paint_offset = FT_NEXT_UOFF3( *p ); + if ( !paint_offset ) + return 0; + + child_table_p = (FT_Byte*)( paint_base + paint_offset ); + + if ( child_table_p < colr->paints_start_v1 || + child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + *child_table_pointer = child_table_p; + return 1; + } + + + static FT_Bool + read_paint( Colr* colr, + FT_Byte* p, + FT_COLR_Paint* apaint ) + { + FT_Byte* paint_base = p; + FT_Byte* child_table_p = NULL; + + + if ( !p || !colr || !colr->table ) + return 0; + + if ( p < colr->paints_start_v1 || + p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p ); + + if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS ) + { + /* Initialize layer iterator/ */ + FT_Byte num_layers; + FT_UInt32 first_layer_index; + + + num_layers = FT_NEXT_BYTE( p ); + if ( num_layers > colr->num_layers_v1 ) + return 0; + + first_layer_index = FT_NEXT_ULONG( p ); + if ( first_layer_index + num_layers > colr->num_layers_v1 ) + return 0; + + apaint->u.colr_layers.layer_iterator.num_layers = num_layers; + apaint->u.colr_layers.layer_iterator.layer = 0; + /* TODO: Check whether pointer is outside colr? */ + apaint->u.colr_layers.layer_iterator.p = + colr->layers_v1 + + LAYER_V1_LIST_NUM_LAYERS_SIZE + + LAYER_V1_LIST_PAINT_OFFSET_SIZE * first_layer_index; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID ) + { + apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p ); + apaint->u.solid.color.alpha = FT_NEXT_SHORT( p ); + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH ) + { + apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + /* + * Grouped below here are all paint formats that have an offset to a + * child paint table as the first entry (for example, a color line or a + * child paint table). Retrieve that and determine whether that paint + * offset is valid first. + */ + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT ) + { + if ( !read_color_line( child_table_p, + &apaint->u.linear_gradient.colorline ) ) + return 0; + + /* + * In order to support variations expose these as FT_Fixed 16.16 values so + * that we can support fractional values after interpolation. + */ + apaint->u.linear_gradient.p0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p2.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p2.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT ) + { + FT_Pos tmp; + + + if ( !read_color_line( child_table_p, + &apaint->u.radial_gradient.colorline ) ) + return 0; + + /* In the OpenType specification, `r0` and `r1` are defined as */ + /* `UFWORD`. Since FreeType doesn't have a corresponding 16.16 */ + /* format we convert to `FWORD` and replace negative values with */ + /* (32bit) `FT_INT_MAX`. */ + + apaint->u.radial_gradient.c0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r0 = tmp < 0 ? FT_INT_MAX : tmp; + + apaint->u.radial_gradient.c1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r1 = tmp < 0 ? FT_INT_MAX : tmp; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT ) + { + if ( !read_color_line( child_table_p, + &apaint->u.sweep_gradient.colorline ) ) + return 0; + + apaint->u.sweep_gradient.center.x = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.center.y = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + apaint->u.sweep_gradient.start_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.end_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + return 1; + } + + if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH ) + { + apaint->u.glyph.paint.p = child_table_p; + apaint->u.glyph.paint.insert_root_transform = 0; + apaint->u.glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM ) + { + apaint->u.transform.paint.p = child_table_p; + apaint->u.transform.paint.insert_root_transform = 0; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + p = child_table_p; + + /* + * The following matrix coefficients are encoded as + * OpenType 16.16 fixed-point values. + */ + apaint->u.transform.affine.xx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.xy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.dx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.dy = FT_NEXT_LONG( p ); + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE ) + { + apaint->u.translate.paint.p = child_table_p; + apaint->u.translate.paint.insert_root_transform = 0; + + apaint->u.translate.dx = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.translate.dy = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + return 1; + } + + else if ( apaint->format == + FT_COLR_PAINTFORMAT_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER ) + { + apaint->u.scale.paint.p = child_table_p; + apaint->u.scale.paint.insert_root_transform = 0; + + /* All scale paints get at least one scale value. */ + apaint->u.scale.scale_x = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + /* Non-uniform ones read an extra y value. */ + if ( apaint->format == + FT_COLR_PAINTFORMAT_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER ) + apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + else + apaint->u.scale.scale_y = apaint->u.scale.scale_x; + + /* Scale paints that have a center read center coordinates, */ + /* otherwise the center is (0,0). */ + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER ) + { + apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + } + else + { + apaint->u.scale.center_x = 0; + apaint->u.scale.center_y = 0; + } + + /* FT 'COLR' v1 API output format always returns fully defined */ + /* structs; we thus set the format to the public API value. */ + apaint->format = FT_COLR_PAINTFORMAT_SCALE; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER ) + { + apaint->u.rotate.paint.p = child_table_p; + apaint->u.rotate.paint.insert_root_transform = 0; + + apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER ) + { + apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.rotate.center_x = 0; + apaint->u.rotate.center_y = 0; + } + + apaint->format = FT_COLR_PAINTFORMAT_ROTATE; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER ) + { + apaint->u.skew.paint.p = child_table_p; + apaint->u.skew.paint.insert_root_transform = 0; + + apaint->u.skew.x_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.y_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER ) + { + apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.skew.center_x = 0; + apaint->u.skew.center_y = 0; + } + + apaint->format = FT_COLR_PAINTFORMAT_SKEW; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE ) + { + FT_UInt composite_mode; + + + apaint->u.composite.source_paint.p = child_table_p; + apaint->u.composite.source_paint.insert_root_transform = 0; + + composite_mode = FT_NEXT_BYTE( p ); + if ( composite_mode >= FT_COLR_COMPOSITE_MAX ) + return 0; + + apaint->u.composite.composite_mode = (FT_Composite_Mode)composite_mode; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + apaint->u.composite.backdrop_paint.p = + child_table_p; + apaint->u.composite.backdrop_paint.insert_root_transform = + 0; + + return 1; + } + + return 0; + } + + + static FT_Bool + find_base_glyph_v1_record( FT_Byte * base_glyph_begin, + FT_UInt num_base_glyph, + FT_UInt glyph_id, + BaseGlyphV1Record *record ) + { + FT_UInt min = 0; + FT_UInt max = num_base_glyph; + + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + + /* + * `base_glyph_begin` is the beginning of `BaseGlyphV1List`; + * skip `numBaseGlyphV1Records` by adding 4 to start binary search + * in the array of `BaseGlyphV1Record`. + */ + FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE; + + FT_UShort gid = FT_NEXT_USHORT( p ); + + + if ( gid < glyph_id ) + min = mid + 1; + else if (gid > glyph_id ) + max = mid; + else + { + record->gid = gid; + record->paint_offset = FT_NEXT_ULONG ( p ); + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* opaque_paint ) + { + Colr* colr = (Colr*)face->colr; + BaseGlyphV1Record base_glyph_v1_record; + FT_Byte* p; + + if ( !colr || !colr->table ) + return 0; + + if ( colr->version < 1 || !colr->num_base_glyphs_v1 || + !colr->base_glyphs_v1 ) + return 0; + + if ( opaque_paint->p ) + return 0; + + if ( !find_base_glyph_v1_record( colr->base_glyphs_v1, + colr->num_base_glyphs_v1, + base_glyph, + &base_glyph_v1_record ) ) + return 0; + + if ( !base_glyph_v1_record.paint_offset || + base_glyph_v1_record.paint_offset > colr->table_size ) + return 0; + + p = (FT_Byte*)( colr->base_glyphs_v1 + + base_glyph_v1_record.paint_offset ); + if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p; + + if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM ) + opaque_paint->insert_root_transform = 1; + else + opaque_paint->insert_root_transform = 0; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + Colr* colr; + + FT_Byte *p, *p1, *clip_base, *limit; + + FT_Byte clip_list_format; + FT_ULong num_clip_boxes, i; + FT_UShort gid_start, gid_end; + FT_UInt32 clip_box_offset; + FT_Byte format; + + const FT_Byte num_corners = 4; + FT_Vector corners[4]; + FT_Byte j; + FT_BBox font_clip_box; + + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + if ( !colr->clip_list ) + return 0; + + p = colr->clip_list; + + /* Limit points to the first byte after the end of the color table. */ + /* Thus, in subsequent limit checks below we need to check whether the */ + /* read pointer is strictly greater than a position offset by certain */ + /* field sizes to the left of that position. */ + limit = (FT_Byte*)colr->table + colr->table_size; + + /* Check whether we can extract one `uint8` and one `uint32`. */ + if ( p > limit - ( 1 + 4 ) ) + return 0; + + clip_base = p; + clip_list_format = FT_NEXT_BYTE ( p ); + + /* Format byte used here to be able to upgrade ClipList for >16bit */ + /* glyph ids; for now we can expect it to be 0. */ + if ( !( clip_list_format == 1 ) ) + return 0; + + num_clip_boxes = FT_NEXT_ULONG( p ); + + /* Check whether we can extract two `uint16` and one `Offset24`, */ + /* `num_clip_boxes` times. */ + if ( colr->table_size / ( 2 + 2 + 3 ) < num_clip_boxes || + p > limit - ( 2 + 2 + 3 ) * num_clip_boxes ) + return 0; + + for ( i = 0; i < num_clip_boxes; ++i ) + { + gid_start = FT_NEXT_USHORT( p ); + gid_end = FT_NEXT_USHORT( p ); + clip_box_offset = FT_NEXT_UOFF3( p ); + + if ( base_glyph >= gid_start && base_glyph <= gid_end ) + { + p1 = (FT_Byte*)( clip_base + clip_box_offset ); + + /* Check whether we can extract one `uint8`. */ + if ( p1 > limit - 1 ) + return 0; + + format = FT_NEXT_BYTE( p1 ); + + if ( format > 1 ) + return 0; + + /* Check whether we can extract four `FWORD`. */ + if ( p1 > limit - ( 2 + 2 + 2 + 2 ) ) + return 0; + + /* `face->root.size->metrics.x_scale` and `y_scale` are factors */ + /* that scale a font unit value in integers to a 26.6 fixed value */ + /* according to the requested size, see for example */ + /* `ft_recompute_scaled_metrics`. */ + font_clip_box.xMin = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.yMin = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.xMax = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.yMax = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + + /* Make 4 corner points (xMin, yMin), (xMax, yMax) and transform */ + /* them. If we we would only transform two corner points and */ + /* span a rectangle based on those, the rectangle may become too */ + /* small to cover the glyph. */ + corners[0].x = font_clip_box.xMin; + corners[1].x = font_clip_box.xMin; + corners[2].x = font_clip_box.xMax; + corners[3].x = font_clip_box.xMax; + + corners[0].y = font_clip_box.yMin; + corners[1].y = font_clip_box.yMax; + corners[2].y = font_clip_box.yMax; + corners[3].y = font_clip_box.yMin; + + for ( j = 0; j < num_corners; ++j ) + { + if ( face->root.internal->transform_flags & 1 ) + FT_Vector_Transform( &corners[j], + &face->root.internal->transform_matrix ); + + if ( face->root.internal->transform_flags & 2 ) + { + corners[j].x += face->root.internal->transform_delta.x; + corners[j].y += face->root.internal->transform_delta.y; + } + } + + clip_box->bottom_left = corners[0]; + clip_box->top_left = corners[1]; + clip_box->top_right = corners[2]; + clip_box->bottom_right = corners[3]; + + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* opaque_paint ) + { + FT_Byte* p = NULL; + FT_Byte* p_first_layer = NULL; + FT_Byte* p_paint = NULL; + FT_UInt32 paint_offset; + + Colr* colr; + + + if ( iterator->layer == iterator->num_layers ) + return 0; + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + /* + * We have an iterator pointing at a paint offset as part of the + * `paintOffset` array in `LayerV1List`. + */ + p = iterator->p; + + /* + * First ensure that p is within COLRv1. + */ + if ( p < colr->layers_v1 || + p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + /* + * Do a cursor sanity check of the iterator. Counting backwards from + * where it stands, we need to end up at a position after the beginning + * of the `LayerV1List` table and not after the end of the + * `LayerV1List`. + */ + p_first_layer = p - + iterator->layer * LAYER_V1_LIST_PAINT_OFFSET_SIZE - + LAYER_V1_LIST_NUM_LAYERS_SIZE; + if ( p_first_layer < (FT_Byte*)colr->layers_v1 ) + return 0; + if ( p_first_layer >= (FT_Byte*)( + colr->layers_v1 + LAYER_V1_LIST_NUM_LAYERS_SIZE + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) ) + return 0; + + paint_offset = + FT_NEXT_ULONG( p ); + opaque_paint->insert_root_transform = + 0; + + p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset ); + + if ( p_paint < colr->paints_start_v1 || + p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p_paint; + + iterator->p = p; + + iterator->layer++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator *iterator ) + { + Colr* colr = (Colr*)face->colr; + + FT_Byte* p; + + + if ( !colr || !colr->table ) + return 0; + + if ( iterator->current_color_stop >= iterator->num_color_stops ) + return 0; + + if ( iterator->p + + ( ( iterator->num_color_stops - iterator->current_color_stop ) * + COLOR_STOP_SIZE ) > + ( (FT_Byte *)colr->table + colr->table_size ) ) + return 0; + + /* Iterator points at first `ColorStop` of `ColorLine`. */ + p = iterator->p; + + color_stop->stop_offset = FT_NEXT_SHORT( p ); + + color_stop->color.palette_index = FT_NEXT_USHORT( p ); + + color_stop->color.alpha = FT_NEXT_SHORT( p ); + + iterator->p = p; + iterator->current_color_stop++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + Colr* colr = (Colr*)face->colr; + FT_OpaquePaint next_paint; + FT_Matrix ft_root_scale; + + if ( !colr || !colr->base_glyphs_v1 || !colr->table ) + return 0; + + if ( opaque_paint.insert_root_transform ) + { + /* 'COLR' v1 glyph information is returned in unscaled coordinates, + * i.e., `FT_Size` is not applied or multiplied into the values. When + * client applications draw color glyphs, they can request to include + * a top-level transform, which includes the active `x_scale` and + * `y_scale` information for scaling the glyph, as well the additional + * transform and translate configured through `FT_Set_Transform`. + * This allows client applications to apply this top-level transform + * to the graphics context first and only once, then have gradient and + * contour scaling applied correctly when performing the additional + * drawing operations for subsequenct paints. Prepare this initial + * transform here. + */ + paint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + + next_paint.p = opaque_paint.p; + next_paint.insert_root_transform = 0; + paint->u.transform.paint = next_paint; + + /* `x_scale` and `y_scale` are in 26.6 format, representing the scale + * factor to get from font units to requested size. However, expected + * return values are in 16.16, so we shift accordingly with rounding. + */ + ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6; + ft_root_scale.xy = 0; + ft_root_scale.yx = 0; + ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6; + + if ( face->root.internal->transform_flags & 1 ) + FT_Matrix_Multiply( &face->root.internal->transform_matrix, + &ft_root_scale ); + + paint->u.transform.affine.xx = ft_root_scale.xx; + paint->u.transform.affine.xy = ft_root_scale.xy; + paint->u.transform.affine.yx = ft_root_scale.yx; + paint->u.transform.affine.yy = ft_root_scale.yy; + + /* The translation is specified in 26.6 format and, according to the + * documentation of `FT_Set_Translate`, is performed on the character + * size given in the last call to `FT_Set_Char_Size`. The + * 'PaintTransform' paint table's `FT_Affine23` format expects + * values in 16.16 format, thus we need to shift by 10 bits. + */ + if ( face->root.internal->transform_flags & 2 ) + { + paint->u.transform.affine.dx = + face->root.internal->transform_delta.x * ( 1 << 10 ); + paint->u.transform.affine.dy = + face->root.internal->transform_delta.y * ( 1 << 10 ); + } + else + { + paint->u.transform.affine.dx = 0; + paint->u.transform.affine.dy = 0; + } + + return 1; + } + + return read_paint( colr, opaque_paint.p, paint ); + } + + FT_LOCAL_DEF( FT_Error ) tt_face_colr_blend_layer( TT_Face face, FT_UInt color_index, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (specification). * - * Copyright (C) 2018-2020 by + * Copyright (C) 2018-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . @@ -42,6 +42,32 @@ FT_UInt *acolor_index, FT_LayerIterator* iterator ); + FT_LOCAL( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + FT_LOCAL( FT_Error ) tt_face_colr_blend_layer( TT_Face face, FT_UInt color_index, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (body). * - * Copyright (C) 2018-2020 by + * Copyright (C) 2018-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (specification). * - * Copyright (C) 2018-2020 by + * Copyright (C) 2018-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Load the basic TrueType kerning table. This doesn't handle * kerning data within the GPOS table at the moment. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -94,7 +94,7 @@ p_next = p; - p += 2; /* skip version */ + p += 2; /* skip version */ length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); @@ -144,7 +144,7 @@ cur_pair = FT_NEXT_ULONG( p ); - if ( cur_pair <= old_pair ) + if ( cur_pair < old_pair ) break; p += 2; @@ -187,11 +187,18 @@ FT_UInt left_glyph, FT_UInt right_glyph ) { - FT_Int result = 0; - FT_UInt count, mask; - FT_Byte* p = face->kern_table; - FT_Byte* p_limit = p + face->kern_table_size; + FT_Int result = 0; + FT_UInt count, mask; + FT_Byte* p; + FT_Byte* p_limit; + + + if ( !face->kern_table ) + return result; + + p = face->kern_table; + p_limit = p + face->kern_table_size; p += 4; mask = 0x0001; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Load the basic TrueType kerning table. This doesn't handle * kerning data within the GPOS table at the moment. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -205,7 +205,6 @@ if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) { - nn--; FT_TRACE2(( "check_table_dir:" " can read only %d table%s in font (instead of %d)\n", nn, nn == 1 ? "" : "s", sfnt->num_tables )); @@ -416,9 +415,9 @@ FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) goto Exit; - FT_TRACE2(( "\n" - " tag offset length checksum\n" - " ----------------------------------\n" )); + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset length checksum\n" )); + FT_TRACE2(( " ----------------------------------\n" )); valid_entries = 0; for ( nn = 0; nn < sfnt.num_tables; nn++ ) @@ -505,7 +504,8 @@ FT_FRAME_EXIT(); - FT_TRACE2(( "table directory loaded\n\n" )); + FT_TRACE2(( "table directory loaded\n" )); + FT_TRACE2(( "\n" )); Exit: return error; @@ -794,8 +794,8 @@ if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) { FT_TRACE0(( "tt_face_load_maxp:" - " too much twilight points in `maxp' table;\n" - " " + " too much twilight points in `maxp' table;\n" )); + FT_TRACE0(( " " " some glyphs might be rendered incorrectly\n" )); maxProfile->maxTwilightPoints = 0xFFFFU - 4; @@ -836,6 +836,8 @@ FT_ULong table_pos, table_len; FT_ULong storage_start, storage_limit; TT_NameTable table; + TT_Name names = NULL; + TT_LangTag langTags = NULL; static const FT_Frame_Field name_table_fields[] = { @@ -916,13 +918,13 @@ storage_start += 2 + 4 * table->numLangTagRecords; /* allocate language tag records array */ - if ( FT_NEW_ARRAY( table->langTags, table->numLangTagRecords ) || - FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) + if ( FT_QNEW_ARRAY( langTags, table->numLangTagRecords ) || + FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) goto Exit; /* load language tags */ { - TT_LangTag entry = table->langTags; + TT_LangTag entry = langTags; TT_LangTag limit = FT_OFFSET( entry, table->numLangTagRecords ); @@ -938,7 +940,13 @@ /* invalid entry; ignore it */ entry->stringLength = 0; } + + /* mark the string as not yet loaded */ + entry->string = NULL; } + + table->langTags = langTags; + langTags = NULL; } FT_FRAME_EXIT(); @@ -947,14 +955,15 @@ } /* allocate name records array */ - if ( FT_NEW_ARRAY( table->names, table->numNameRecords ) || - FT_FRAME_ENTER( table->numNameRecords * 12 ) ) + if ( FT_QNEW_ARRAY( names, table->numNameRecords ) || + FT_FRAME_ENTER( table->numNameRecords * 12 ) ) goto Exit; /* load name records */ { - TT_Name entry = table->names; + TT_Name entry = names; FT_UInt count = table->numNameRecords; + FT_UInt valid = 0; for ( ; count > 0; count-- ) @@ -987,15 +996,20 @@ } } + /* mark the string as not yet converted */ + entry->string = NULL; + + valid++; entry++; } /* reduce array size to the actually used elements */ - count = (FT_UInt)( entry - table->names ); - (void)FT_RENEW_ARRAY( table->names, - table->numNameRecords, - count ); - table->numNameRecords = count; + FT_MEM_QRENEW_ARRAY( names, + table->numNameRecords, + valid ); + table->names = names; + names = NULL; + table->numNameRecords = valid; } FT_FRAME_EXIT(); @@ -1004,6 +1018,8 @@ face->num_names = (FT_UShort)table->numNameRecords; Exit: + FT_FREE( names ); + FT_FREE( langTags ); return error; } @@ -1311,6 +1327,12 @@ if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) return error; + if ( post->FormatType != 0x00030000L && + post->FormatType != 0x00025000L && + post->FormatType != 0x00020000L && + post->FormatType != 0x00010000L ) + return FT_THROW( Invalid_Post_Table_Format ); + /* we don't load the glyph names, we do that in another */ /* module (ttpost). */ @@ -1410,8 +1432,8 @@ FT_Error error; FT_Memory memory = stream->memory; - FT_UInt j,num_ranges; - TT_GaspRange gaspranges = NULL; + FT_UShort j, num_ranges; + TT_GaspRange gasp_ranges = NULL; /* the gasp table is optional */ @@ -1422,8 +1444,8 @@ if ( FT_FRAME_ENTER( 4L ) ) goto Exit; - face->gasp.version = FT_GET_USHORT(); - face->gasp.numRanges = FT_GET_USHORT(); + face->gasp.version = FT_GET_USHORT(); + num_ranges = FT_GET_USHORT(); FT_FRAME_EXIT(); @@ -1435,29 +1457,31 @@ goto Exit; } - num_ranges = face->gasp.numRanges; - FT_TRACE3(( "numRanges: %u\n", num_ranges )); + FT_TRACE3(( "numRanges: %hu\n", num_ranges )); - if ( FT_QNEW_ARRAY( face->gasp.gaspRanges, num_ranges ) || - FT_FRAME_ENTER( num_ranges * 4L ) ) + if ( FT_QNEW_ARRAY( gasp_ranges, num_ranges ) || + FT_FRAME_ENTER( num_ranges * 4L ) ) goto Exit; - gaspranges = face->gasp.gaspRanges; - for ( j = 0; j < num_ranges; j++ ) { - gaspranges[j].maxPPEM = FT_GET_USHORT(); - gaspranges[j].gaspFlag = FT_GET_USHORT(); + gasp_ranges[j].maxPPEM = FT_GET_USHORT(); + gasp_ranges[j].gaspFlag = FT_GET_USHORT(); FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", j, - gaspranges[j].maxPPEM, - gaspranges[j].gaspFlag )); + gasp_ranges[j].maxPPEM, + gasp_ranges[j].gaspFlag )); } + face->gasp.gaspRanges = gasp_ranges; + gasp_ranges = NULL; + face->gasp.numRanges = num_ranges; + FT_FRAME_EXIT(); Exit: + FT_FREE( gasp_ranges ); return error; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (body). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (specification). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -158,7 +158,7 @@ static FT_Error load_format_20( TT_Face face, FT_Stream stream, - FT_ULong post_limit ) + FT_ULong post_len ) { FT_Memory memory = stream->memory; FT_Error error; @@ -168,6 +168,7 @@ FT_UShort* glyph_indices = NULL; FT_Char** name_strings = NULL; + FT_Byte* strings = NULL; if ( FT_READ_USHORT( num_glyphs ) ) @@ -179,7 +180,8 @@ /* There already exist fonts which have more than 32768 glyph names */ /* in this table, so the test for this threshold has been dropped. */ - if ( num_glyphs > face->max_profile.numGlyphs ) + if ( num_glyphs > face->max_profile.numGlyphs || + (FT_ULong)num_glyphs * 2UL > post_len - 2 ) { error = FT_THROW( Invalid_File_Format ); goto Exit; @@ -190,7 +192,7 @@ FT_Int n; - if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || FT_FRAME_ENTER( num_glyphs * 2L ) ) goto Fail; @@ -223,60 +225,56 @@ } /* now load the name strings */ + if ( num_names ) { FT_UShort n; + FT_ULong p; - if ( FT_NEW_ARRAY( name_strings, num_names ) ) + post_len -= (FT_ULong)num_glyphs * 2UL + 2; + + if ( FT_QALLOC( strings, post_len + 1 ) || + FT_STREAM_READ( strings, post_len ) || + FT_QNEW_ARRAY( name_strings, num_names ) ) goto Fail; - for ( n = 0; n < num_names; n++ ) + /* convert from Pascal- to C-strings and set pointers */ + for ( p = 0, n = 0; p < post_len && n < num_names; n++ ) { - FT_UInt len; - - - if ( FT_STREAM_POS() >= post_limit ) - break; - else - { - FT_TRACE6(( "load_format_20: %ld byte left in post table\n", - post_limit - FT_STREAM_POS() )); + FT_UInt len = strings[p]; - if ( FT_READ_BYTE( len ) ) - goto Fail1; - } - if ( len > post_limit || - FT_STREAM_POS() > post_limit - len ) + if ( len > 63U ) { - FT_Int d = (FT_Int)post_limit - (FT_Int)FT_STREAM_POS(); - - - FT_ERROR(( "load_format_20:" - " exceeding string length (%d)," - " truncating at end of post table (%d byte left)\n", - len, d )); - len = (FT_UInt)FT_MAX( 0, d ); + error = FT_THROW( Invalid_File_Format ); + goto Fail; } - if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || - FT_STREAM_READ( name_strings[n], len ) ) - goto Fail1; - - name_strings[n][len] = '\0'; + strings[p] = 0; + name_strings[n] = (FT_Char*)strings + p + 1; + p += len + 1; } + strings[post_len] = 0; + /* deal with missing or insufficient string data */ if ( n < num_names ) { + if ( post_len == 0 ) + { + /* fake empty string */ + if ( FT_QREALLOC( strings, 1, 2 ) ) + goto Fail; + + post_len = 1; + strings[post_len] = 0; + } + FT_ERROR(( "load_format_20:" " all entries in post table are already parsed," " using NULL names for gid %d - %d\n", n, num_names - 1 )); for ( ; n < num_names; n++ ) - if ( FT_NEW_ARRAY( name_strings[n], 1 ) ) - goto Fail1; - else - name_strings[n][0] = '\0'; + name_strings[n] = (FT_Char*)strings + post_len; } } @@ -292,17 +290,9 @@ } return FT_Err_Ok; - Fail1: - { - FT_UShort n; - - - for ( n = 0; n < num_names; n++ ) - FT_FREE( name_strings[n] ); - } - Fail: FT_FREE( name_strings ); + FT_FREE( strings ); FT_FREE( glyph_indices ); Exit: @@ -313,7 +303,7 @@ static FT_Error load_format_25( TT_Face face, FT_Stream stream, - FT_ULong post_limit ) + FT_ULong post_len ) { FT_Memory memory = stream->memory; FT_Error error; @@ -321,7 +311,7 @@ FT_Int num_glyphs; FT_Char* offset_table = NULL; - FT_UNUSED( post_limit ); + FT_UNUSED( post_len ); if ( FT_READ_USHORT( num_glyphs ) ) @@ -336,7 +326,7 @@ goto Exit; } - if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || + if ( FT_QNEW_ARRAY( offset_table, num_glyphs ) || FT_STREAM_READ( offset_table, num_glyphs ) ) goto Fail; @@ -384,7 +374,6 @@ FT_Error error; FT_Fixed format; FT_ULong post_len; - FT_ULong post_limit; /* get a stream for the face's resource */ @@ -395,8 +384,6 @@ if ( error ) goto Exit; - post_limit = FT_STREAM_POS() + post_len; - format = face->postscript.FormatType; /* go to beginning of subtable */ @@ -404,10 +391,10 @@ goto Exit; /* now read postscript table */ - if ( format == 0x00020000L ) - error = load_format_20( face, stream, post_limit ); - else if ( format == 0x00025000L ) - error = load_format_25( face, stream, post_limit ); + if ( format == 0x00020000L && post_len >= 34 ) + error = load_format_20( face, stream, post_len - 32 ); + else if ( format == 0x00025000L && post_len >= 34 ) + error = load_format_25( face, stream, post_len - 32 ); else error = FT_THROW( Invalid_File_Format ); @@ -433,17 +420,19 @@ if ( format == 0x00020000L ) { TT_Post_20 table = &names->names.format_20; - FT_UShort n; FT_FREE( table->glyph_indices ); table->num_glyphs = 0; - for ( n = 0; n < table->num_names; n++ ) - FT_FREE( table->glyph_names[n] ); + if ( table->num_names ) + { + table->glyph_names[0]--; + FT_FREE( table->glyph_names[0] ); - FT_FREE( table->glyph_names ); - table->num_names = 0; + FT_FREE( table->glyph_names ); + table->num_names = 0; + } } else if ( format == 0x00025000L ) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h 2022-07-14 08:05:38.000000000 +0000 @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (body). * - * Copyright (C) 2005-2020 by + * Copyright (C) 2005-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Copyright 2013 by Google, Inc. @@ -172,13 +172,8 @@ goto Exit; } - /* we currently don't support bit 1; however, it is better to */ - /* draw at least something... */ if ( flags == 3 ) - FT_TRACE1(( "tt_face_load_sbit_strikes:" - " sbix overlay not supported yet\n" - " " - " expect bad rendering results\n" )); + face->root.face_flags |= FT_FACE_FLAG_SBIX_OVERLAY; /* * Count the number of strikes available in the table. We are a bit @@ -240,8 +235,8 @@ if ( !face->ebdt_size ) { FT_TRACE2(( "tt_face_load_sbit_strikes:" - " no embedded bitmap data table found;\n" - " " + " no embedded bitmap data table found;\n" )); + FT_TRACE2(( " " " resetting number of strikes to zero\n" )); face->sbit_num_strikes = 0; } @@ -345,8 +340,8 @@ if ( metrics->ascender == 0 ) { FT_TRACE2(( "tt_face_load_strike_metrics:" - " sanitizing invalid ascender and descender\n" - " " + " sanitizing invalid ascender and descender\n" )); + FT_TRACE2(( " " " values for strike %ld (%dppem, %dppem)\n", strike_index, metrics->x_ppem, metrics->y_ppem )); @@ -374,8 +369,8 @@ if ( metrics->height == 0 ) { FT_TRACE2(( "tt_face_load_strike_metrics:" - " sanitizing invalid height value\n" - " " + " sanitizing invalid height value\n" )); + FT_TRACE2(( " " " for strike (%d, %d)\n", metrics->x_ppem, metrics->y_ppem )); metrics->height = metrics->y_ppem * 64; @@ -726,6 +721,9 @@ pitch = bitmap->pitch; line = bitmap->buffer; + if ( !line ) + goto Exit; + width = decoder->metrics->width; height = decoder->metrics->height; @@ -1573,17 +1571,34 @@ if ( !error ) { - FT_Short abearing; + FT_Short abearing; /* not used here */ FT_UShort aadvance; tt_face_get_metrics( face, FALSE, glyph_index, &abearing, &aadvance ); metrics->horiBearingX = (FT_Short)originOffsetX; - metrics->horiBearingY = (FT_Short)( -originOffsetY + metrics->height ); + metrics->vertBearingX = (FT_Short)originOffsetX; + + metrics->horiBearingY = (FT_Short)( originOffsetY + metrics->height ); + metrics->vertBearingY = (FT_Short)originOffsetY; + metrics->horiAdvance = (FT_UShort)( aadvance * face->root.size->metrics.x_ppem / face->header.Units_Per_EM ); + + if ( face->vertical_info ) + tt_face_get_metrics( face, TRUE, glyph_index, &abearing, &aadvance ); + else if ( face->os2.version != 0xFFFFU ) + aadvance = (FT_UShort)FT_ABS( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + aadvance = (FT_UShort)FT_ABS( face->horizontal.Ascender - + face->horizontal.Descender ); + + metrics->vertAdvance = (FT_UShort)( aadvance * + face->root.size->metrics.x_ppem / + face->header.Units_Per_EM ); } return error; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * WOFF2 Font table tags (base). * - * Copyright (C) 2019-2020 by + * Copyright (C) 2019-2022 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,6 +17,9 @@ #include + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + #include "woff2tags.h" /* @@ -28,10 +31,10 @@ * * for details. */ - FT_LOCAL_DEF( FT_ULong ) + FT_LOCAL_DEF( FT_Tag ) woff2_known_tags( FT_Byte index ) { - const FT_ULong known_tags[63] = + static const FT_Tag known_tags[63] = { FT_MAKE_TAG('c', 'm', 'a', 'p'), /* 0 */ FT_MAKE_TAG('h', 'e', 'a', 'd'), /* 1 */ @@ -105,5 +108,12 @@ return known_tags[index]; } +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int _woff2tags_dummy; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + /* END */ diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h 2022-07-14 08:05:38.000000000 +0000 @@ -2,9 +2,9 @@ * * woff2tags.h * - * WOFFF2 Font table tags (specification). + * WOFF2 Font table tags (specification). * - * Copyright (C) 2019-2020 by + * Copyright (C) 2019-2022 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,10 +26,12 @@ FT_BEGIN_HEADER +#ifdef FT_CONFIG_OPTION_USE_BROTLI - FT_LOCAL( FT_ULong ) + FT_LOCAL( FT_Tag ) woff2_known_tags( FT_Byte index ); +#endif FT_END_HEADER diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * A new `perfect' anti-aliasing renderer (body). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -149,14 +149,10 @@ #define FT_INT_MAX INT_MAX #define FT_ULONG_MAX ULONG_MAX -#define ADD_LONG( a, b ) \ - (long)( (unsigned long)(a) + (unsigned long)(b) ) -#define SUB_LONG( a, b ) \ - (long)( (unsigned long)(a) - (unsigned long)(b) ) -#define MUL_LONG( a, b ) \ - (long)( (unsigned long)(a) * (unsigned long)(b) ) -#define NEG_LONG( a ) \ - (long)( -(unsigned long)(a) ) +#define ADD_INT( a, b ) \ + (int)( (unsigned int)(a) + (unsigned int)(b) ) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) #define ft_memset memset @@ -168,10 +164,11 @@ typedef ptrdiff_t FT_PtrDist; -#define ErrRaster_Invalid_Mode -2 -#define ErrRaster_Invalid_Outline -1 -#define ErrRaster_Invalid_Argument -3 -#define ErrRaster_Memory_Overflow -4 +#define Smooth_Err_Ok 0 +#define Smooth_Err_Invalid_Outline -1 +#define Smooth_Err_Cannot_Render_Glyph -2 +#define Smooth_Err_Invalid_Argument -3 +#define Smooth_Err_Raster_Overflow -4 #define FT_BEGIN_HEADER #define FT_END_HEADER @@ -229,23 +226,26 @@ #define FT_ERROR( varformat ) FT_Message varformat #endif -#define FT_THROW( e ) \ - ( FT_Throw( FT_ERR_CAT( ErrRaster_, e ), \ - __LINE__, \ - __FILE__ ) | \ - FT_ERR_CAT( ErrRaster_, e ) ) +#define FT_THROW( e ) \ + ( FT_Throw( FT_ERR_CAT( Smooth_Err_, e ), \ + __LINE__, \ + __FILE__ ) | \ + FT_ERR_CAT( Smooth_Err_, e ) ) #else /* !FT_DEBUG_LEVEL_TRACE */ #define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */ #define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ -#define FT_THROW( e ) FT_ERR_CAT( ErrRaster_, e ) - +#define FT_THROW( e ) FT_ERR_CAT( Smooth_Err_, e ) #endif /* !FT_DEBUG_LEVEL_TRACE */ +#define FT_Trace_Enable() do { } while ( 0 ) /* nothing */ +#define FT_Trace_Disable() do { } while ( 0 ) /* nothing */ + + #define FT_DEFINE_OUTLINE_FUNCS( class_, \ move_to_, line_to_, \ conic_to_, cubic_to_, \ @@ -278,6 +278,8 @@ #else /* !STANDALONE_ */ +#include +#include FT_CONFIG_CONFIG_H #include "ftgrays.h" #include #include @@ -286,10 +288,6 @@ #include "ftsmerrs.h" -#define Smooth_Err_Invalid_Mode Smooth_Err_Cannot_Render_Glyph -#define Smooth_Err_Memory_Overflow Smooth_Err_Out_Of_Memory -#define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory - #endif /* !STANDALONE_ */ @@ -335,7 +333,9 @@ #define PIXEL_BITS 8 #define ONE_PIXEL ( 1 << PIXEL_BITS ) +#undef TRUNC #define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS ) +#undef FRACT #define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) #if PIXEL_BITS >= 6 @@ -362,7 +362,7 @@ } \ FT_END_STMNT -#ifdef __arm__ +#if defined( __GNUC__ ) && __GNUC__ < 7 && defined( __arm__ ) /* Work around a bug specific to GCC which make the compiler fail to */ /* optimize a division and modulo operation on the same parameters */ /* into a single call to `__aeabi_idivmod'. See */ @@ -382,14 +382,58 @@ #endif /* __arm__ */ - /* These macros speed up repetitive divisions by replacing them */ - /* with multiplications and right shifts. */ -#define FT_UDIVPREP( c, b ) \ - long b ## _r = c ? (long)( FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \ - : 0 -#define FT_UDIV( a, b ) \ - (TCoord)( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \ - ( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) ) + /* Calculating coverages for a slanted line requires a division each */ + /* time the line crosses from cell to cell. These macros speed up */ + /* the repetitive divisions by replacing them with multiplications */ + /* and right shifts so that at most two divisions are performed for */ + /* each slanted line. Nevertheless, these divisions are noticeable */ + /* in the overall performance because flattened curves produce a */ + /* very large number of slanted lines. */ + /* */ + /* The division results here are always within ONE_PIXEL. Therefore */ + /* the shift magnitude should be at least PIXEL_BITS wider than the */ + /* divisors to provide sufficient accuracy of the multiply-shift. */ + /* It should not exceed (64 - PIXEL_BITS) to prevent overflowing and */ + /* leave enough room for 64-bit unsigned multiplication however. */ +#define FT_UDIVPREP( c, b ) \ + FT_Int64 b ## _r = c ? (FT_Int64)0xFFFFFFFF / ( b ) : 0 +#define FT_UDIV( a, b ) \ + (TCoord)( ( (FT_UInt64)( a ) * (FT_UInt64)( b ## _r ) ) >> 32 ) + + + /* Scale area and apply fill rule to calculate the coverage byte. */ + /* The top fill bit is used for the non-zero rule. The eighth */ + /* fill bit is used for the even-odd rule. The higher coverage */ + /* bytes are either clamped for the non-zero-rule or discarded */ + /* later for the even-odd rule. */ +#define FT_FILL_RULE( coverage, area, fill ) \ + FT_BEGIN_STMNT \ + coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); \ + if ( coverage & fill ) \ + coverage = ~coverage; \ + if ( coverage > 255 && fill & INT_MIN ) \ + coverage = 255; \ + FT_END_STMNT + + + /* It is faster to write small spans byte-by-byte than calling */ + /* `memset'. This is mainly due to the cost of the function call. */ +#define FT_GRAY_SET( d, s, count ) \ + FT_BEGIN_STMNT \ + unsigned char* q = d; \ + switch ( count ) \ + { \ + case 7: *q++ = (unsigned char)s; /* fall through */ \ + case 6: *q++ = (unsigned char)s; /* fall through */ \ + case 5: *q++ = (unsigned char)s; /* fall through */ \ + case 4: *q++ = (unsigned char)s; /* fall through */ \ + case 3: *q++ = (unsigned char)s; /* fall through */ \ + case 2: *q++ = (unsigned char)s; /* fall through */ \ + case 1: *q = (unsigned char)s; /* fall through */ \ + case 0: break; \ + default: FT_MEM_SET( d, s, count ); \ + } \ + FT_END_STMNT /************************************************************************** @@ -432,7 +476,7 @@ #endif /* FT_Span buffer size for direct rendering only */ -#define FT_MAX_GRAY_SPANS 10 +#define FT_MAX_GRAY_SPANS 16 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ @@ -447,28 +491,24 @@ { ft_jmp_buf jump_buffer; - TCoord ex, ey; - TCoord min_ex, max_ex; + TCoord min_ex, max_ex; /* min and max integer pixel coordinates */ TCoord min_ey, max_ey; + TCoord count_ey; /* same as (max_ey - min_ey) */ - TArea area; - TCoord cover; - int invalid; + PCell cell; /* current cell */ + PCell cell_free; /* call allocation next free slot */ + PCell cell_null; /* last cell, used as dumpster and limit */ - PCell* ycells; - PCell cells; - FT_PtrDist max_cells; - FT_PtrDist num_cells; + PCell* ycells; /* array of cell linked-lists; one per */ + /* vertical coordinate in the current band */ - TPos x, y; + TPos x, y; /* last point position */ - FT_Outline outline; - TPixmap target; + FT_Outline outline; /* input outline */ + TPixmap target; /* target pixmap */ FT_Raster_Span_Func render_span; void* render_span_data; - FT_Span spans[FT_MAX_GRAY_SPANS]; - int num_spans; } gray_TWorker, *gray_PWorker; @@ -476,17 +516,25 @@ #pragma warning( pop ) #endif - #ifndef FT_STATIC_RASTER #define ras (*worker) #else static gray_TWorker ras; #endif + /* The |x| value of the null cell. Must be the largest possible */ + /* integer value stored in a `TCell.x` field. */ +#define CELL_MAX_X_VALUE INT_MAX + + +#define FT_INTEGRATE( ras, a, b ) \ + ras.cell->cover = ADD_INT( ras.cell->cover, a ), \ + ras.cell->area = ADD_INT( ras.cell->area, (a) * (TArea)(b) ) + typedef struct gray_TRaster_ { - void* memory; + void* memory; } gray_TRaster, *gray_PRaster; @@ -508,7 +556,7 @@ printf( "%3d:", y ); - for ( ; cell != NULL; cell = cell->next ) + for ( ; cell != ras.cell_null; cell = cell->next ) printf( " (%3d, c:%4d, a:%6d)", cell->x, cell->cover, cell->area ); printf( "\n" ); @@ -520,81 +568,67 @@ /************************************************************************** * - * Record the current cell in the linked list. + * Set the current cell to a new position. */ static void - gray_record_cell( RAS_ARG ) + gray_set_cell( RAS_ARG_ TCoord ex, + TCoord ey ) { - PCell *pcell, cell; - TCoord x = ras.ex; - + /* Move the cell pointer to a new position in the linked list. We use */ + /* a dumpster null cell for everything outside of the clipping region */ + /* during the render phase. This means that: */ + /* */ + /* . the new vertical position must be within min_ey..max_ey-1. */ + /* . the new horizontal position must be strictly less than max_ex */ + /* */ + /* Note that if a cell is to the left of the clipping region, it is */ + /* actually set to the (min_ex-1) horizontal position. */ - pcell = &ras.ycells[ras.ey - ras.min_ey]; - while ( ( cell = *pcell ) ) - { - if ( cell->x > x ) - break; + TCoord ey_index = ey - ras.min_ey; - if ( cell->x == x ) - goto Found; - pcell = &cell->next; - } + if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex ) + ras.cell = ras.cell_null; + else + { + PCell* pcell = ras.ycells + ey_index; + PCell cell; - if ( ras.num_cells >= ras.max_cells ) - ft_longjmp( ras.jump_buffer, 1 ); - /* insert new cell */ - cell = ras.cells + ras.num_cells++; - cell->x = x; - cell->area = ras.area; - cell->cover = ras.cover; + ex = FT_MAX( ex, ras.min_ex - 1 ); - cell->next = *pcell; - *pcell = cell; + while ( 1 ) + { + cell = *pcell; - return; + if ( cell->x > ex ) + break; - Found: - /* update old cell */ - cell->area += ras.area; - cell->cover += ras.cover; - } + if ( cell->x == ex ) + goto Found; + pcell = &cell->next; + } - /************************************************************************** - * - * Set the current cell to a new position. - */ - static void - gray_set_cell( RAS_ARG_ TCoord ex, - TCoord ey ) - { - /* Move the cell pointer to a new position. We set the `invalid' */ - /* flag to indicate that the cell isn't part of those we're interested */ - /* in during the render phase. This means that: */ - /* */ - /* . the new vertical position must be within min_ey..max_ey-1. */ - /* . the new horizontal position must be strictly less than max_ex */ - /* */ - /* Note that if a cell is to the left of the clipping region, it is */ - /* actually set to the (min_ex-1) horizontal position. */ + /* insert new cell */ + cell = ras.cell_free++; + if ( cell >= ras.cell_null ) + ft_longjmp( ras.jump_buffer, 1 ); - /* record the current one if it is valid and substantial */ - if ( !ras.invalid && ( ras.area || ras.cover ) ) - gray_record_cell( RAS_VAR ); + cell->x = ex; + cell->area = 0; + cell->cover = 0; - ras.area = 0; - ras.cover = 0; - ras.ex = FT_MAX( ex, ras.min_ex - 1 ); - ras.ey = ey; + cell->next = *pcell; + *pcell = cell; - ras.invalid = ( ey >= ras.max_ey || ey < ras.min_ey || - ex >= ras.max_ex ); + Found: + ras.cell = cell; + } } -#ifndef FT_LONG64 +#ifndef FT_INT64 /************************************************************************** * @@ -622,8 +656,8 @@ return; } - fx1 = FRACT( x1 ); - fx2 = FRACT( x2 ); + fx1 = FRACT( x1 ); + fx2 = FRACT( x2 ); /* everything is located in a single cell. That is easy! */ /* */ @@ -655,10 +689,9 @@ /* XXX: y-delta and x-delta below should be related. */ FT_DIV_MOD( TCoord, p, dx, delta, mod ); - ras.area += (TArea)( ( fx1 + first ) * delta ); - ras.cover += delta; - y1 += delta; - ex1 += incr; + FT_INTEGRATE( ras, delta, fx1 + first ); + y1 += delta; + ex1 += incr; gray_set_cell( RAS_VAR_ ex1, ey ); if ( ex1 != ex2 ) @@ -679,10 +712,9 @@ delta++; } - ras.area += (TArea)( ONE_PIXEL * delta ); - ras.cover += delta; - y1 += delta; - ex1 += incr; + FT_INTEGRATE( ras, delta, ONE_PIXEL ); + y1 += delta; + ex1 += incr; gray_set_cell( RAS_VAR_ ex1, ey ); } while ( ex1 != ex2 ); } @@ -690,10 +722,7 @@ fx1 = ONE_PIXEL - first; End: - dy = y2 - y1; - - ras.area += (TArea)( ( fx1 + fx2 ) * dy ); - ras.cover += dy; + FT_INTEGRATE( ras, y2 - y1, fx1 + fx2 ); } @@ -736,7 +765,6 @@ { TCoord ex = TRUNC( ras.x ); TCoord two_fx = FRACT( ras.x ) << 1; - TArea area; if ( dy > 0) @@ -750,27 +778,23 @@ incr = -1; } - delta = first - fy1; - ras.area += (TArea)two_fx * delta; - ras.cover += delta; - ey1 += incr; + delta = first - fy1; + FT_INTEGRATE( ras, delta, two_fx); + ey1 += incr; gray_set_cell( RAS_VAR_ ex, ey1 ); delta = first + first - ONE_PIXEL; - area = (TArea)two_fx * delta; while ( ey1 != ey2 ) { - ras.area += area; - ras.cover += delta; - ey1 += incr; + FT_INTEGRATE( ras, delta, two_fx); + ey1 += incr; gray_set_cell( RAS_VAR_ ex, ey1 ); } - delta = fy2 - ONE_PIXEL + first; - ras.area += (TArea)two_fx * delta; - ras.cover += delta; + delta = fy2 - ONE_PIXEL + first; + FT_INTEGRATE( ras, delta, two_fx); goto End; } @@ -883,8 +907,7 @@ do { fy2 = ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * fx1 * 2; + FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); fy1 = 0; ey1++; gray_set_cell( RAS_VAR_ ex1, ey1 ); @@ -893,8 +916,7 @@ do { fy2 = 0; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * fx1 * 2; + FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); fy1 = ONE_PIXEL; ey1--; gray_set_cell( RAS_VAR_ ex1, ey1 ); @@ -902,7 +924,7 @@ } else /* any other line */ { - TPos prod = dx * (TPos)fy1 - dy * (TPos)fx1; + FT_Int64 prod = dx * (FT_Int64)fy1 - dy * (FT_Int64)fx1; FT_UDIVPREP( ex1 != ex2, dx ); FT_UDIVPREP( ey1 != ey2, dy ); @@ -912,72 +934,308 @@ /* also easily updated when moving from one cell to the next. */ do { - if ( prod <= 0 && - prod - dx * ONE_PIXEL > 0 ) /* left */ + if ( prod - dx * ONE_PIXEL > 0 && + prod <= 0 ) /* left */ { fx2 = 0; fy2 = FT_UDIV( -prod, -dx ); prod -= dy * ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); fx1 = ONE_PIXEL; fy1 = fy2; ex1--; } - else if ( prod - dx * ONE_PIXEL <= 0 && - prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */ + else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 && + prod - dx * ONE_PIXEL <= 0 ) /* up */ { prod -= dx * ONE_PIXEL; fx2 = FT_UDIV( -prod, dy ); fy2 = ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); fx1 = fx2; fy1 = 0; ey1++; } - else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && - prod + dy * ONE_PIXEL >= 0 ) /* right */ + else if ( prod + dy * ONE_PIXEL >= 0 && + prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 ) /* right */ { prod += dy * ONE_PIXEL; fx2 = ONE_PIXEL; fy2 = FT_UDIV( prod, dx ); - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); fx1 = 0; fy1 = fy2; ex1++; } - else /* ( prod + dy * ONE_PIXEL < 0 && - prod > 0 ) down */ + else /* ( prod > 0 && + prod + dy * ONE_PIXEL < 0 ) down */ { fx2 = FT_UDIV( prod, -dy ); fy2 = 0; prod += dx * ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); fx1 = fx2; fy1 = ONE_PIXEL; ey1--; } gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ex1 != ex2 || ey1 != ey2 ); } fx2 = FRACT( to_x ); fy2 = FRACT( to_y ); - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); End: - ras.x = to_x; - ras.y = to_y; + ras.x = to_x; + ras.y = to_y; } #endif + /* + * Benchmarking shows that using DDA to flatten the quadratic Bézier arcs + * is slightly faster in the following cases: + * + * - When the host CPU is 64-bit. + * - When SSE2 SIMD registers and instructions are available (even on + * x86). + * + * For other cases, using binary splits is actually slightly faster. + */ +#if defined( __SSE2__ ) || \ + defined( __x86_64__ ) || \ + defined( _M_AMD64 ) || \ + ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 ) +# define FT_SSE2 1 +#else +# define FT_SSE2 0 +#endif + +#if FT_SSE2 || \ + defined( __aarch64__ ) || \ + defined( _M_ARM64 ) +# define BEZIER_USE_DDA 1 +#else +# define BEZIER_USE_DDA 0 +#endif + + /* + * For now, the code that depends on `BEZIER_USE_DDA` requires `FT_Int64` + * to be defined. If `FT_INT64` is not defined, meaning there is no + * 64-bit type available, disable it to avoid compilation errors. See for + * example https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071. + */ +#if !defined( FT_INT64 ) +# undef BEZIER_USE_DDA +# define BEZIER_USE_DDA 0 +#endif + +#if BEZIER_USE_DDA + +#if FT_SSE2 +# include +#endif + +#define LEFT_SHIFT( a, b ) (FT_Int64)( (FT_UInt64)(a) << (b) ) + + + static void + gray_render_conic( RAS_ARG_ const FT_Vector* control, + const FT_Vector* to ) + { + FT_Vector p0, p1, p2; + TPos ax, ay, bx, by, dx, dy; + int shift; + + FT_Int64 rx, ry; + FT_Int64 qx, qy; + FT_Int64 px, py; + + FT_UInt count; + + + p0.x = ras.x; + p0.y = ras.y; + p1.x = UPSCALE( control->x ); + p1.y = UPSCALE( control->y ); + p2.x = UPSCALE( to->x ); + p2.y = UPSCALE( to->y ); + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( p0.y ) >= ras.max_ey && + TRUNC( p1.y ) >= ras.max_ey && + TRUNC( p2.y ) >= ras.max_ey ) || + ( TRUNC( p0.y ) < ras.min_ey && + TRUNC( p1.y ) < ras.min_ey && + TRUNC( p2.y ) < ras.min_ey ) ) + { + ras.x = p2.x; + ras.y = p2.y; + return; + } + + bx = p1.x - p0.x; + by = p1.y - p0.y; + ax = p2.x - p1.x - bx; /* p0.x + p2.x - 2 * p1.x */ + ay = p2.y - p1.y - by; /* p0.y + p2.y - 2 * p1.y */ + + dx = FT_ABS( ax ); + dy = FT_ABS( ay ); + if ( dx < dy ) + dx = dy; + + if ( dx <= ONE_PIXEL / 4 ) + { + gray_render_line( RAS_VAR_ p2.x, p2.y ); + return; + } + + /* We can calculate the number of necessary bisections because */ + /* each bisection predictably reduces deviation exactly 4-fold. */ + /* Even 32-bit deviation would vanish after 16 bisections. */ + shift = 0; + do + { + dx >>= 2; + shift += 1; + + } while ( dx > ONE_PIXEL / 4 ); + + /* + * The (P0,P1,P2) arc equation, for t in [0,1] range: + * + * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2 + * + * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2 + * = P0 + 2*B*t + A*t^2 + * + * for A = P0 + P2 - 2*P1 + * and B = P1 - P0 + * + * Let's consider the difference when advancing by a small + * parameter h: + * + * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t + * + * And then its own difference: + * + * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant) + * + * Since R is always a constant, it is possible to compute + * successive positions with: + * + * P = P0 + * Q = Q(h,0) = 2*B*h + A*h*h + * R = 2*A*h*h + * + * loop: + * P += Q + * Q += R + * EMIT(P) + * + * To ensure accurate results, perform computations on 64-bit + * values, after scaling them by 2^32. + * + * h = 1 / 2^N + * + * R << 32 = 2 * A << (32 - N - N) + * = A << (33 - 2*N) + * + * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N)) + * = (B << (33 - N)) + (A << (32 - 2*N)) + */ + +#if FT_SSE2 + /* Experience shows that for small shift values, */ + /* SSE2 is actually slower. */ + if ( shift > 2 ) + { + union + { + struct { FT_Int64 ax, ay, bx, by; } i; + struct { __m128i a, b; } vec; + + } u; + + union + { + struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i; + __m128i vec; + + } v; + + __m128i a, b; + __m128i r, q, q2; + __m128i p; + + + u.i.ax = ax; + u.i.ay = ay; + u.i.bx = bx; + u.i.by = by; + + a = _mm_load_si128( &u.vec.a ); + b = _mm_load_si128( &u.vec.b ); + + r = _mm_slli_epi64( a, 33 - 2 * shift ); + q = _mm_slli_epi64( b, 33 - shift ); + q2 = _mm_slli_epi64( a, 32 - 2 * shift ); + + q = _mm_add_epi64( q2, q ); + + v.i.px_lo = 0; + v.i.px_hi = p0.x; + v.i.py_lo = 0; + v.i.py_hi = p0.y; + + p = _mm_load_si128( &v.vec ); + + for ( count = 1U << shift; count > 0; count-- ) + { + p = _mm_add_epi64( p, q ); + q = _mm_add_epi64( q, r ); + + _mm_store_si128( &v.vec, p ); + + gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi ); + } + + return; + } +#endif /* FT_SSE2 */ + + rx = LEFT_SHIFT( ax, 33 - 2 * shift ); + ry = LEFT_SHIFT( ay, 33 - 2 * shift ); + + qx = LEFT_SHIFT( bx, 33 - shift ) + LEFT_SHIFT( ax, 32 - 2 * shift ); + qy = LEFT_SHIFT( by, 33 - shift ) + LEFT_SHIFT( ay, 32 - 2 * shift ); + + px = LEFT_SHIFT( p0.x, 32 ); + py = LEFT_SHIFT( p0.y, 32 ); + + for ( count = 1U << shift; count > 0; count-- ) + { + px += qx; + py += qy; + qx += rx; + qy += ry; + + gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ), + (FT_Pos)( py >> 32 ) ); + } + } + +#else /* !BEZIER_USE_DDA */ + + /* + * Note that multiple attempts to speed up the function below + * with SSE2 intrinsics, using various data layouts, have turned + * out to be slower than the non-SIMD code below. + */ static void gray_split_conic( FT_Vector* base ) { @@ -1007,7 +1265,7 @@ FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */ FT_Vector* arc = bez_stack; TPos dx, dy; - int draw, split; + int draw; arc[0].x = UPSCALE( to->x ); @@ -1050,7 +1308,9 @@ /* many times as there are trailing zeros in the counter. */ do { - split = draw & ( -draw ); /* isolate the rightmost 1-bit */ + int split = draw & ( -draw ); /* isolate the rightmost 1-bit */ + + while ( ( split >>= 1 ) ) { gray_split_conic( arc ); @@ -1063,7 +1323,17 @@ } while ( --draw ); } +#endif /* !BEZIER_USE_DDA */ + + /* + * For cubic Bézier, binary splits are still faster than DDA + * because the splits are adaptive to how quickly each sub-arc + * approaches their chord trisection points. + * + * It might be useful to experiment with SSE2 to speed up + * `gray_split_cubic`, though. + */ static void gray_split_cubic( FT_Vector* base ) { @@ -1205,125 +1475,133 @@ static void - gray_hline( RAS_ARG_ TCoord x, - TCoord y, - TArea coverage, - TCoord acount ) + gray_sweep( RAS_ARG ) { - /* scale the coverage from 0..(ONE_PIXEL*ONE_PIXEL*2) to 0..256 */ - coverage >>= PIXEL_BITS * 2 + 1 - 8; + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; - /* compute the line's coverage depending on the outline fill rule */ - if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) - { - coverage &= 511; - if ( coverage >= 256 ) - coverage = 511 - coverage; - } - else /* default non-zero winding rule */ + for ( y = ras.min_ey; y < ras.max_ey; y++ ) { - if ( coverage < 0 ) - coverage = ~coverage; /* the same as -coverage - 1 */ + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; - if ( coverage >= 256 ) - coverage = 255; - } + unsigned char* line = ras.target.origin - ras.target.pitch * y; - if ( ras.num_spans >= 0 ) /* for FT_RASTER_FLAG_DIRECT only */ - { - FT_Span* span = ras.spans + ras.num_spans++; + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; - span->x = (short)x; - span->len = (unsigned short)acount; - span->coverage = (unsigned char)coverage; - if ( ras.num_spans == FT_MAX_GRAY_SPANS ) - { - /* flush the span buffer and reset the count */ - ras.render_span( y, ras.num_spans, ras.spans, ras.render_span_data ); - ras.num_spans = 0; - } - } - else - { - unsigned char* q = ras.target.origin - ras.target.pitch * y + x; - unsigned char c = (unsigned char)coverage; + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, cell->x - x ); + } + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; - /* For small-spans it is faster to do it by ourselves than - * calling `memset'. This is mainly due to the cost of the - * function call. - */ - switch ( acount ) + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + line[cell->x] = (unsigned char)coverage; + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ { - case 7: - *q++ = c; - /* fall through */ - case 6: - *q++ = c; - /* fall through */ - case 5: - *q++ = c; - /* fall through */ - case 4: - *q++ = c; - /* fall through */ - case 3: - *q++ = c; - /* fall through */ - case 2: - *q++ = c; - /* fall through */ - case 1: - *q = c; - /* fall through */ - case 0: - break; - default: - FT_MEM_SET( q, c, acount ); + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, ras.max_ex - x ); } } } static void - gray_sweep( RAS_ARG ) + gray_sweep_direct( RAS_ARG ) { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; int y; + FT_Span span[FT_MAX_GRAY_SPANS]; + int n = 0; + for ( y = ras.min_ey; y < ras.max_ey; y++ ) { PCell cell = ras.ycells[y - ras.min_ey]; TCoord x = ras.min_ex; TArea cover = 0; - TArea area; - for ( ; cell != NULL; cell = cell->next ) + for ( ; cell != ras.cell_null; cell = cell->next ) { + TArea area; + + if ( cover != 0 && cell->x > x ) - gray_hline( RAS_VAR_ x, y, cover, cell->x - x ); + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( cell->x - x ); + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); area = cover - cell->area; if ( area != 0 && cell->x >= ras.min_ex ) - gray_hline( RAS_VAR_ cell->x, y, area, 1 ); + { + FT_FILL_RULE( coverage, area, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)cell->x; + span[n].len = 1; + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } x = cell->x + 1; } - if ( cover != 0 ) - gray_hline( RAS_VAR_ x, y, cover, ras.max_ex - x ); + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( ras.max_ex - x ); + + ++n; + } - if ( ras.num_spans > 0 ) /* for FT_RASTER_FLAG_DIRECT only */ + if ( n ) { /* flush the span buffer and reset the count */ - ras.render_span( y, ras.num_spans, ras.spans, ras.render_span_data ); - ras.num_spans = 0; + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; } } } @@ -1604,7 +1882,7 @@ } FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); - return 0; + return Smooth_Err_Ok; Exit: FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error )); @@ -1645,18 +1923,15 @@ if ( continued ) FT_Trace_Enable(); - if ( !ras.invalid ) - gray_record_cell( RAS_VAR ); - - FT_TRACE7(( "band [%d..%d]: %ld cell%s\n", + FT_TRACE7(( "band [%d..%d]: %ld cell%s remaining/\n", ras.min_ey, ras.max_ey, - ras.num_cells, - ras.num_cells == 1 ? "" : "s" )); + ras.cell_null - ras.cell_free, + ras.cell_null - ras.cell_free == 1 ? "" : "s" )); } else { - error = FT_THROW( Memory_Overflow ); + error = FT_THROW( Raster_Overflow ); FT_TRACE7(( "band [%d..%d]: to be bisected\n", ras.min_ey, ras.max_ey )); @@ -1682,7 +1957,16 @@ int continued = 0; + /* Initialize the null cell at the end of the poll. */ + ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1; + ras.cell_null->x = CELL_MAX_X_VALUE; + ras.cell_null->area = 0; + ras.cell_null->cover = 0; + ras.cell_null->next = NULL; + /* set up vertical bands */ + ras.ycells = (PCell*)buffer; + if ( height > n ) { /* two divisions rounded up */ @@ -1690,13 +1974,6 @@ height = ( height + n - 1 ) / n; } - /* memory management */ - n = ( height * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / sizeof ( TCell ); - - ras.cells = buffer + n; - ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n ); - ras.ycells = (PCell*)buffer; - for ( y = yMin; y < yMax; ) { ras.min_ey = y; @@ -1710,27 +1987,37 @@ do { TCoord width = band[0] - band[1]; + TCoord w; int error; - FT_MEM_ZERO( ras.ycells, height * sizeof ( PCell ) ); + for ( w = 0; w < width; ++w ) + ras.ycells[w] = ras.cell_null; - ras.num_cells = 0; - ras.invalid = 1; + /* memory management: skip ycells */ + n = ( (size_t)width * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / + sizeof ( TCell ); + + ras.cell_free = buffer + n; + ras.cell = ras.cell_null; ras.min_ey = band[1]; ras.max_ey = band[0]; + ras.count_ey = width; error = gray_convert_glyph_inner( RAS_VAR, continued ); continued = 1; if ( !error ) { - gray_sweep( RAS_VAR ); + if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */ + gray_sweep_direct( RAS_VAR ); + else + gray_sweep( RAS_VAR ); band--; continue; } - else if ( error != ErrRaster_Memory_Overflow ) - return 1; + else if ( error != Smooth_Err_Raster_Overflow ) + return error; /* render pool overflow; we will reduce the render band by half */ width >>= 1; @@ -1739,7 +2026,7 @@ if ( width == 0 ) { FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); - return 1; + return FT_THROW( Raster_Overflow ); } band++; @@ -1748,7 +2035,7 @@ } while ( band >= bands ); } - return 0; + return Smooth_Err_Ok; } @@ -1769,14 +2056,14 @@ /* this version does not support monochrome rendering */ if ( !( params->flags & FT_RASTER_FLAG_AA ) ) - return FT_THROW( Invalid_Mode ); + return FT_THROW( Cannot_Render_Glyph ); if ( !outline ) return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ if ( outline->n_points == 0 || outline->n_contours <= 0 ) - return 0; + return Smooth_Err_Ok; if ( !outline->contours || !outline->points ) return FT_THROW( Invalid_Outline ); @@ -1790,11 +2077,10 @@ if ( params->flags & FT_RASTER_FLAG_DIRECT ) { if ( !params->gray_spans ) - return 0; + return Smooth_Err_Ok; ras.render_span = (FT_Raster_Span_Func)params->gray_spans; ras.render_span_data = params->user; - ras.num_spans = 0; ras.min_ex = params->clip_box.xMin; ras.min_ey = params->clip_box.yMin; @@ -1809,7 +2095,7 @@ /* nothing to do */ if ( !target_map->width || !target_map->rows ) - return 0; + return Smooth_Err_Ok; if ( !target_map->buffer ) return FT_THROW( Invalid_Argument ); @@ -1824,7 +2110,6 @@ ras.render_span = (FT_Raster_Span_Func)NULL; ras.render_span_data = NULL; - ras.num_spans = -1; /* invalid */ ras.min_ex = 0; ras.min_ey = 0; @@ -1834,7 +2119,7 @@ /* exit if nothing to do */ if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey ) - return 0; + return Smooth_Err_Ok; return gray_convert_glyph( RAS_VAR ); } @@ -1871,19 +2156,17 @@ #else /* !STANDALONE_ */ static int - gray_raster_new( FT_Memory memory, - FT_Raster* araster ) + gray_raster_new( FT_Memory memory, + gray_PRaster* araster ) { FT_Error error; gray_PRaster raster = NULL; - *araster = 0; - if ( !FT_ALLOC( raster, sizeof ( gray_TRaster ) ) ) - { + if ( !FT_NEW( raster ) ) raster->memory = memory; - *araster = (FT_Raster)raster; - } + + *araster = raster; return error; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * FreeType smooth renderer declaration * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * smooth renderer error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (body). * - * Copyright (C) 2000-2020 by + * Copyright (C) 2000-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType font driver implementation (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -108,7 +108,7 @@ return error; } - FT_TRACE0(( "tt_property_set: missing property `%s'\n", + FT_TRACE2(( "tt_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -135,7 +135,7 @@ return error; } - FT_TRACE0(( "tt_property_get: missing property `%s'\n", + FT_TRACE2(( "tt_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -354,7 +354,16 @@ #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ - FT_Request_Metrics( size->face, req ); + { + FT_Error err = FT_Request_Metrics( size->face, req ); + + + if ( err ) + { + error = err; + goto Exit; + } + } if ( FT_IS_SCALABLE( size->face ) ) { @@ -382,6 +391,7 @@ #endif } + Exit: return error; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level TrueType driver interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -197,10 +197,17 @@ } #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - if ( !loader->linear_def ) +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* With the incremental interface, these values are set by */ + /* a call to `tt_get_metrics_incremental'. */ + if ( face->root.internal->incremental_interface == NULL ) +#endif { - loader->linear_def = 1; - loader->linear = advance_width; + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } } return FT_Err_Ok; @@ -210,8 +217,8 @@ #ifdef FT_CONFIG_OPTION_INCREMENTAL static void - tt_get_metrics_incr_overrides( TT_Loader loader, - FT_UInt glyph_index ) + tt_get_metrics_incremental( TT_Loader loader, + FT_UInt glyph_index ) { TT_Face face = loader->face; @@ -451,7 +458,7 @@ (void*)&load->exec->glyphIns, n_ins ); - load->exec->glyphSize = (FT_UShort)tmp; + load->exec->glyphSize = (FT_UInt)tmp; if ( error ) return error; @@ -736,12 +743,14 @@ subglyph->transform.xx / 65536.0, subglyph->transform.yy / 65536.0 )); else if ( subglyph->flags & WE_HAVE_A_2X2 ) - FT_TRACE7(( " scaling: xx=%f, yx=%f\n" - " xy=%f, yy=%f\n", + { + FT_TRACE7(( " scaling: xx=%f, yx=%f\n", subglyph->transform.xx / 65536.0, - subglyph->transform.yx / 65536.0, + subglyph->transform.yx / 65536.0 )); + FT_TRACE7(( " xy=%f, yy=%f\n", subglyph->transform.xy / 65536.0, subglyph->transform.yy / 65536.0 )); + } subglyph++; } @@ -1383,7 +1392,7 @@ FT_READ_USHORT( n_ins ) ) return error; - FT_TRACE5(( " Instructions size = %d\n", n_ins )); + FT_TRACE5(( " Instructions size = %hu\n", n_ins )); /* check it */ max_ins = loader->face->max_profile.maxSizeOfInstructions; @@ -1391,10 +1400,10 @@ { /* don't trust `maxSizeOfInstructions'; */ /* only do a rough safety check */ - if ( (FT_Int)n_ins > loader->byte_len ) + if ( n_ins > loader->byte_len ) { FT_TRACE1(( "TT_Process_Composite_Glyph:" - " too many instructions (%d) for glyph with length %d\n", + " too many instructions (%hu) for glyph with length %u\n", n_ins, loader->byte_len )); return FT_THROW( Too_Many_Hints ); } @@ -1677,7 +1686,7 @@ FT_ZERO( &inc_stream ); FT_Stream_OpenMemory( &inc_stream, glyph_data.pointer, - (FT_ULong)glyph_data.length ); + glyph_data.length ); loader->stream = &inc_stream; } @@ -1685,8 +1694,7 @@ #endif /* FT_CONFIG_OPTION_INCREMENTAL */ - offset = tt_face_get_location( face, glyph_index, - (FT_UInt*)&loader->byte_len ); + offset = tt_face_get_location( face, glyph_index, &loader->byte_len ); if ( loader->byte_len > 0 ) { @@ -1705,7 +1713,7 @@ error = face->access_glyph_frame( loader, glyph_index, face->glyf_offset + offset, - (FT_UInt)loader->byte_len ); + loader->byte_len ); if ( error ) goto Exit; @@ -1739,13 +1747,11 @@ if ( loader->byte_len == 0 || loader->n_contours == 0 ) { - /* must initialize points before (possibly) overriding */ - /* glyph metrics from the incremental interface */ - tt_loader_set_pp( loader ); - #ifdef FT_CONFIG_OPTION_INCREMENTAL - tt_get_metrics_incr_overrides( loader, glyph_index ); + tt_get_metrics_incremental( loader, glyph_index ); #endif + tt_loader_set_pp( loader ); + #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT @@ -1828,13 +1834,11 @@ goto Exit; } - /* must initialize phantom points before (possibly) overriding */ - /* glyph metrics from the incremental interface */ - tt_loader_set_pp( loader ); - #ifdef FT_CONFIG_OPTION_INCREMENTAL - tt_get_metrics_incr_overrides( loader, glyph_index ); + tt_get_metrics_incremental( loader, glyph_index ); #endif + tt_loader_set_pp( loader ); + /***********************************************************************/ /***********************************************************************/ @@ -1844,7 +1848,7 @@ /* (which consists of 10 bytes) */ error = face->access_glyph_frame( loader, glyph_index, face->glyf_offset + offset + 10, - (FT_UInt)loader->byte_len - 10 ); + loader->byte_len - 10 ); if ( error ) goto Exit; @@ -1898,7 +1902,7 @@ /* clear the nodes filled by sibling chains */ node = ft_list_get_node_at( &loader->composites, recurse_count ); for ( node2 = node; node2; node2 = node2->next ) - node2->data = (void*)FT_ULONG_MAX; + node2->data = (void*)-1; /* check whether we already have a composite glyph with this index */ if ( FT_List_Find( &loader->composites, @@ -1915,7 +1919,7 @@ else { - if ( FT_NEW( node ) ) + if ( FT_QNEW( node ) ) goto Exit; node->data = FT_UINT_TO_POINTER( glyph_index ); FT_List_Add( &loader->composites, node ); @@ -2100,7 +2104,7 @@ FT_UInt num_base_subgs = gloader->base.num_subglyphs; FT_Stream old_stream = loader->stream; - FT_Int old_byte_len = loader->byte_len; + FT_UInt old_byte_len = loader->byte_len; FT_GlyphLoader_Add( gloader ); @@ -2226,10 +2230,6 @@ FT_UInt glyph_index ) { TT_Face face = loader->face; -#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \ - defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); -#endif FT_BBox bbox; FT_Fixed y_scale; @@ -2252,53 +2252,10 @@ glyph->metrics.horiBearingX = bbox.xMin; glyph->metrics.horiBearingY = bbox.yMax; - glyph->metrics.horiAdvance = SUB_LONG(loader->pp2.x, loader->pp1.x); - - /* Adjust advance width to the value contained in the hdmx table */ - /* unless FT_LOAD_COMPUTE_METRICS is set or backward compatibility */ - /* mode of the v40 interpreter is active. See `ttinterp.h' for */ - /* details on backward compatibility mode. */ - if ( -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && - ( loader->exec && loader->exec->backward_compatibility ) ) && -#endif - !face->postscript.isFixedPitch && - IS_HINTED( loader->load_flags ) && - !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) ) - { - FT_Byte* widthp; - - - widthp = tt_face_get_device_metrics( face, - size->metrics->x_ppem, - glyph_index ); - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) - { - FT_Bool ignore_x_mode; - - - ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) != - FT_RENDER_MODE_MONO ); - - if ( widthp && - ( ( ignore_x_mode && loader->exec->compatible_widths ) || - !ignore_x_mode || - SPH_OPTION_BITMAP_WIDTHS ) ) - glyph->metrics.horiAdvance = *widthp * 64; - } - else - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - { - if ( widthp ) - glyph->metrics.horiAdvance = *widthp * 64; - } - } + if ( loader->widthp ) + glyph->metrics.horiAdvance = loader->widthp[glyph_index] * 64; + else + glyph->metrics.horiAdvance = SUB_LONG(loader->pp2.x, loader->pp1.x); /* set glyph dimensions */ glyph->metrics.width = SUB_LONG( bbox.xMax, bbox.xMin ); @@ -2713,6 +2670,9 @@ error = tt_size_run_prep( size, pedantic ); if ( error ) return error; + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; } /* check whether the cvt program has disabled hinting */ @@ -2728,12 +2688,58 @@ /* note that this flag can also be modified in a glyph's bytecode */ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 && exec->GS.instruct_control & 4 ) - exec->ignore_x_mode = 0; -#endif + exec->ignore_x_mode = FALSE; +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * Toggle backward compatibility according to what font wants, except + * when + * + * 1) we have a `tricky' font that heavily relies on the interpreter to + * render glyphs correctly, for example DFKai-SB, or + * 2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested. + * + * In those cases, backward compatibility needs to be turned off to get + * correct rendering. The rendering is then completely up to the + * font's programming. + * + */ + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + subpixel_hinting_lean && + !FT_IS_TRICKY( glyph->face ) ) + exec->backward_compatibility = !( exec->GS.instruct_control & 4 ); + else + exec->backward_compatibility = FALSE; +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); loader->exec = exec; loader->instructions = exec->glyphIns; + + /* Use the hdmx table if any unless FT_LOAD_COMPUTE_METRICS */ + /* is set or backward compatibility mode of the v38 or v40 */ + /* interpreters is active. See `ttinterp.h' for details on */ + /* backward compatibility mode. */ + if ( IS_HINTED( loader->load_flags ) && + !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + exec->backward_compatibility ) && +#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + !( driver->interpreter_version == TT_INTERPRETER_VERSION_38 && + !SPH_OPTION_BITMAP_WIDTHS && + FT_LOAD_TARGET_MODE( loader->load_flags ) != + FT_RENDER_MODE_MONO && + exec->compatible_widths ) && +#endif + !face->postscript.isFixedPitch ) + { + loader->widthp = size->widthp; + } + else + loader->widthp = NULL; } #endif /* TT_USE_BYTECODE_INTERPRETER */ @@ -2781,11 +2787,12 @@ * A function used to load a single glyph within a given glyph slot, * for a given size. * - * @Input: + * @InOut: * glyph :: * A handle to a target slot object where the glyph * will be loaded. * + * @Input: * size :: * A handle to the source face size at which the glyph * must be scaled/loaded. @@ -2890,8 +2897,12 @@ } else { - if ( FT_IS_SCALABLE( glyph->face ) ) + if ( FT_IS_SCALABLE( glyph->face ) || + FT_HAS_SBIX( glyph->face ) ) { + TT_Face face = (TT_Face)glyph->face; + + /* for the bbox we need the header only */ (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE ); (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE ); @@ -2899,6 +2910,35 @@ glyph->linearHoriAdvance = loader.linear; glyph->linearVertAdvance = loader.vadvance; + /* Bitmaps from the 'sbix' table need special treatment: */ + /* if there is a glyph contour, the bitmap origin must be */ + /* shifted to be relative to the lower left corner of the */ + /* glyph bounding box, also taking the left-side bearing */ + /* (or top bearing) into account. */ + if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX && + loader.n_contours > 0 ) + { + FT_Int bitmap_left; + FT_Int bitmap_top; + + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* This is a guess, since Apple's CoreText engine doesn't */ + /* really do vertical typesetting. */ + bitmap_left = loader.bbox.xMin; + bitmap_top = loader.top_bearing; + } + else + { + bitmap_left = loader.left_bearing; + bitmap_top = loader.bbox.yMin; + } + + glyph->bitmap_left += FT_MulFix( bitmap_left, x_scale ) >> 6; + glyph->bitmap_top += FT_MulFix( bitmap_top, y_scale ) >> 6; + } + /* sanity checks: if `xxxAdvance' in the sbit metric */ /* structure isn't set, use `linearXXXAdvance' */ if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance ) @@ -2913,6 +2953,12 @@ } } + if ( load_flags & FT_LOAD_SBITS_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ @@ -2922,16 +2968,81 @@ goto Exit; } - if ( load_flags & FT_LOAD_SBITS_ONLY ) +#ifdef FT_CONFIG_OPTION_SVG + + /* check for OT-SVG */ + if ( ( load_flags & FT_LOAD_COLOR ) && ( (TT_Face)glyph->face )->svg ) + { + SFNT_Service sfnt; + + FT_Short leftBearing; + FT_Short topBearing; + FT_UShort advanceX; + FT_UShort advanceY; + + + FT_TRACE3(( "Trying to load SVG glyph\n" )); + sfnt = (SFNT_Service)( (TT_Face)glyph->face )->sfnt; + + error = sfnt->load_svg_doc( glyph, glyph_index ); + if ( !error ) + { + TT_Face face = (TT_Face)glyph->face; + + + FT_TRACE3(( "Successfully loaded SVG glyph\n" )); + + glyph->format = FT_GLYPH_FORMAT_SVG; + + sfnt->get_metrics( face, + FALSE, + glyph_index, + &leftBearing, + &advanceX ); + sfnt->get_metrics( face, + TRUE, + glyph_index, + &topBearing, + &advanceY ); + + advanceX = (FT_UShort)FT_MulDiv( advanceX, + glyph->face->size->metrics.x_ppem, + glyph->face->units_per_EM ); + advanceY = (FT_UShort)FT_MulDiv( advanceY, + glyph->face->size->metrics.y_ppem, + glyph->face->units_per_EM ); + + glyph->metrics.horiAdvance = advanceX << 6; + glyph->metrics.vertAdvance = advanceY << 6; + + return error; + } + + FT_TRACE3(( "Failed to load SVG glyph\n" )); + } + + /* return immediately if we only want SVG glyphs */ + if ( load_flags & FT_LOAD_SVG_ONLY ) { error = FT_THROW( Invalid_Argument ); goto Exit; } +#endif /* FT_CONFIG_OPTION_SVG */ + error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); if ( error ) goto Exit; + /* done if we are only interested in the `hdmx` advance */ + if ( load_flags & FT_LOAD_ADVANCE_ONLY && + !( load_flags & FT_LOAD_VERTICAL_LAYOUT ) && + loader.widthp ) + { + glyph->metrics.horiAdvance = loader.widthp[glyph_index] * 64; + goto Done; + } + glyph->format = FT_GLYPH_FORMAT_OUTLINE; glyph->num_subglyphs = 0; glyph->outline.flags = 0; @@ -3010,6 +3121,7 @@ glyph->outline.n_points, glyph->outline.flags )); + Done: tt_loader_done( &loader ); Exit: diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. * * This file is part of the FreeType project, and may only be used, @@ -151,9 +151,7 @@ FT_UInt i, j; FT_UShort first; FT_Memory memory = stream->memory; - FT_Error error = FT_Err_Ok; - - FT_UNUSED( error ); + FT_Error error; *point_cnt = 0; @@ -178,7 +176,7 @@ /* in the nested loops below we increase `i' twice; */ /* it is faster to simply allocate one more slot */ /* than to add another test within the loop */ - if ( FT_NEW_ARRAY( points, n + 1 ) ) + if ( FT_QNEW_ARRAY( points, n + 1 ) ) return NULL; *point_cnt = n; @@ -264,55 +262,78 @@ FT_Fixed *deltas = NULL; FT_UInt runcnt, cnt; FT_UInt i, j; + FT_UInt bytes_used; FT_Memory memory = stream->memory; - FT_Error error = FT_Err_Ok; - - FT_UNUSED( error ); + FT_Error error; - if ( delta_cnt > size ) - { - FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" )); + if ( FT_QNEW_ARRAY( deltas, delta_cnt ) ) return NULL; - } - if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) - return NULL; + i = 0; + bytes_used = 0; - i = 0; - while ( i < delta_cnt ) + while ( i < delta_cnt && bytes_used < size ) { runcnt = FT_GET_BYTE(); cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; + bytes_used++; + if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) { - /* `runcnt' zeroes get added */ + /* `cnt` + 1 zeroes get added */ for ( j = 0; j <= cnt && i < delta_cnt; j++ ) deltas[i++] = 0; } else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) { - /* `runcnt' shorts from the stack */ + /* `cnt` + 1 shorts from the stack */ + bytes_used += 2 * ( cnt + 1 ); + if ( bytes_used > size ) + { + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of short deltas too large\n" )); + goto Fail; + } + for ( j = 0; j <= cnt && i < delta_cnt; j++ ) deltas[i++] = FT_intToFixed( FT_GET_SHORT() ); } else { - /* `runcnt' signed bytes from the stack */ + /* `cnt` + 1 signed bytes from the stack */ + bytes_used += cnt + 1; + if ( bytes_used > size ) + { + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of byte deltas too large\n" )); + goto Fail; + } + for ( j = 0; j <= cnt && i < delta_cnt; j++ ) deltas[i++] = FT_intToFixed( FT_GET_CHAR() ); } if ( j <= cnt ) { - /* bad format */ - FT_FREE( deltas ); - return NULL; + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of deltas too large\n" )); + goto Fail; } } + if ( i < delta_cnt ) + { + FT_TRACE1(( "ft_var_readpackeddeltas: not enough deltas\n" )); + goto Fail; + } + return deltas; + + Fail: + FT_FREE( deltas ); + return NULL; } @@ -336,14 +357,12 @@ FT_Memory memory = stream->memory; GX_Blend blend = face->blend; GX_AVarSegment segment; - FT_Error error = FT_Err_Ok; + FT_Error error; FT_Long version; FT_Long axisCount; FT_Int i, j; FT_ULong table_len; - FT_UNUSED( error ); - FT_TRACE2(( "AVAR " )); @@ -371,12 +390,13 @@ if ( axisCount != (FT_Long)blend->mmvar->num_axis ) { - FT_TRACE2(( "ft_var_load_avar: number of axes in `avar' and `fvar'\n" - " table are different\n" )); + FT_TRACE2(( "ft_var_load_avar:" + " number of axes in `avar' and `fvar'\n" )); + FT_TRACE2(( " table are different\n" )); goto Exit; } - if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) + if ( FT_QNEW_ARRAY( blend->avar_segment, axisCount ) ) goto Exit; segment = &blend->avar_segment[0]; @@ -385,8 +405,8 @@ FT_TRACE5(( " axis %d:\n", i )); segment->pairCount = FT_GET_USHORT(); - if ( (FT_ULong)segment->pairCount * 4 > table_len || - FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) + if ( (FT_ULong)segment->pairCount * 4 > table_len || + FT_QNEW_ARRAY( segment->correspondence, segment->pairCount ) ) { /* Failure. Free everything we have done so far. We must do */ /* it right now since loading the `avar' table is optional. */ @@ -395,7 +415,6 @@ FT_FREE( blend->avar_segment[j].correspondence ); FT_FREE( blend->avar_segment ); - blend->avar_segment = NULL; goto Exit; } @@ -431,7 +450,8 @@ FT_UShort format; FT_ULong region_offset; FT_UInt i, j, k; - FT_UInt shortDeltaCount; + FT_UInt wordDeltaCount; + FT_Bool long_words; GX_Blend blend = face->blend; GX_ItemVarData varData; @@ -466,7 +486,7 @@ /* make temporary copy of item variation data offsets; */ /* we will parse region list first, then come back */ - if ( FT_NEW_ARRAY( dataOffsetArray, itemStore->dataCount ) ) + if ( FT_QNEW_ARRAY( dataOffsetArray, itemStore->dataCount ) ) goto Exit; for ( i = 0; i < itemStore->dataCount; i++ ) @@ -486,13 +506,22 @@ if ( itemStore->axisCount != (FT_Long)blend->mmvar->num_axis ) { FT_TRACE2(( "ft_var_load_item_variation_store:" - " number of axes in item variation store\n" - " " + " number of axes in item variation store\n" )); + FT_TRACE2(( " " " and `fvar' table are different\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } + /* new constraint in OpenType 1.8.4 */ + if ( itemStore->regionCount >= 32768U ) + { + FT_TRACE2(( "ft_var_load_item_variation_store:" + " too many variation region tables\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + if ( FT_NEW_ARRAY( itemStore->varRegionList, itemStore->regionCount ) ) goto Exit; @@ -537,15 +566,18 @@ goto Exit; if ( FT_READ_USHORT( varData->itemCount ) || - FT_READ_USHORT( shortDeltaCount ) || + FT_READ_USHORT( wordDeltaCount ) || FT_READ_USHORT( varData->regionIdxCount ) ) goto Exit; + long_words = !!( wordDeltaCount & 0x8000 ); + wordDeltaCount &= 0x7FFF; + /* check some data consistency */ - if ( shortDeltaCount > varData->regionIdxCount ) + if ( wordDeltaCount > varData->regionIdxCount ) { FT_TRACE2(( "bad short count %d or region count %d\n", - shortDeltaCount, + wordDeltaCount, varData->regionIdxCount )); error = FT_THROW( Invalid_Table ); goto Exit; @@ -581,39 +613,52 @@ /* Parse delta set. */ /* */ - /* On input, deltas are (shortDeltaCount + regionIdxCount) bytes */ - /* each; on output, deltas are expanded to `regionIdxCount' shorts */ - /* each. */ + /* On input, deltas are (wordDeltaCount + regionIdxCount) bytes */ + /* each if `long_words` isn't set, and twice as much otherwise. */ + /* */ + /* On output, deltas are expanded to `regionIdxCount` shorts each. */ if ( FT_NEW_ARRAY( varData->deltaSet, varData->regionIdxCount * varData->itemCount ) ) goto Exit; - /* the delta set is stored as a 2-dimensional array of shorts; */ - /* sign-extend signed bytes to signed shorts */ - for ( j = 0; j < varData->itemCount * varData->regionIdxCount; ) + /* the delta set is stored as a 2-dimensional array of shorts */ + if ( long_words ) { - for ( k = 0; k < shortDeltaCount; k++, j++ ) + /* new in OpenType 1.9, currently for 'COLR' table only; */ + /* the deltas are interpreted as 16.16 fixed-point scaling values */ + + /* not supported yet */ + + error = FT_THROW( Invalid_Table ); + goto Exit; + } + else + { + for ( j = 0; j < varData->itemCount * varData->regionIdxCount; ) { - /* read the short deltas */ - FT_Short delta; + for ( k = 0; k < wordDeltaCount; k++, j++ ) + { + /* read the short deltas */ + FT_Short delta; - if ( FT_READ_SHORT( delta ) ) - goto Exit; + if ( FT_READ_SHORT( delta ) ) + goto Exit; - varData->deltaSet[j] = delta; - } + varData->deltaSet[j] = delta; + } - for ( ; k < varData->regionIdxCount; k++, j++ ) - { - /* read the (signed) byte deltas */ - FT_Char delta; + for ( ; k < varData->regionIdxCount; k++, j++ ) + { + /* read the (signed) byte deltas */ + FT_Char delta; - if ( FT_READ_CHAR( delta ) ) - goto Exit; + if ( FT_READ_CHAR( delta ) ) + goto Exit; - varData->deltaSet[j] = delta; + varData->deltaSet[j] = delta; + } } } } @@ -629,37 +674,66 @@ ft_var_load_delta_set_index_mapping( TT_Face face, FT_ULong offset, GX_DeltaSetIdxMap map, - GX_ItemVarStore itemStore ) + GX_ItemVarStore itemStore, + FT_ULong table_len ) { FT_Stream stream = FT_FACE_STREAM( face ); FT_Memory memory = stream->memory; - FT_Error error; + FT_Error error; - FT_UShort format; - FT_UInt entrySize; - FT_UInt innerBitCount; - FT_UInt innerIndexMask; - FT_UInt i, j; + FT_Byte format; + FT_Byte entryFormat; + FT_UInt entrySize; + FT_UInt innerBitCount; + FT_UInt innerIndexMask; + FT_ULong i; + FT_UInt j; - if ( FT_STREAM_SEEK( offset ) || - FT_READ_USHORT( format ) || - FT_READ_USHORT( map->mapCount ) ) + if ( FT_STREAM_SEEK( offset ) || + FT_READ_BYTE( format ) || + FT_READ_BYTE( entryFormat ) ) goto Exit; - if ( format & 0xFFC0 ) + if ( format == 0 ) + { + if ( FT_READ_USHORT( map->mapCount ) ) + goto Exit; + } + else if ( format == 1 ) /* new in OpenType 1.9 */ + { + if ( FT_READ_ULONG( map->mapCount ) ) + goto Exit; + } + else { FT_TRACE2(( "bad map format %d\n", format )); error = FT_THROW( Invalid_Table ); goto Exit; } + if ( entryFormat & 0xC0 ) + { + FT_TRACE2(( "bad entry format %d\n", format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + /* bytes per entry: 1, 2, 3, or 4 */ - entrySize = ( ( format & 0x0030 ) >> 4 ) + 1; - innerBitCount = ( format & 0x000F ) + 1; + entrySize = ( ( entryFormat & 0x30 ) >> 4 ) + 1; + innerBitCount = ( entryFormat & 0x0F ) + 1; innerIndexMask = ( 1 << innerBitCount ) - 1; + /* rough sanity check */ + if ( map->mapCount * entrySize > table_len ) + { + FT_TRACE1(( "ft_var_load_delta_set_index_mapping:" + " invalid number of delta-set index mappings\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + if ( FT_NEW_ARRAY( map->innerIndex, map->mapCount ) ) goto Exit; @@ -688,7 +762,7 @@ if ( outerIndex >= itemStore->dataCount ) { - FT_TRACE2(( "outerIndex[%d] == %d out of range\n", + FT_TRACE2(( "outerIndex[%ld] == %d out of range\n", i, outerIndex )); error = FT_THROW( Invalid_Table ); @@ -701,7 +775,7 @@ if ( innerIndex >= itemStore->varData[outerIndex].itemCount ) { - FT_TRACE2(( "innerIndex[%d] == %d out of range\n", + FT_TRACE2(( "innerIndex[%ld] == %d out of range\n", i, innerIndex )); error = FT_THROW( Invalid_Table ); @@ -826,7 +900,8 @@ face, table_offset + widthMap_offset, &table->widthMap, - &table->itemStore ); + &table->itemStore, + table_len ); if ( error ) goto Exit; } @@ -1515,8 +1590,9 @@ if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) { - FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n" - " table are different\n" )); + FT_TRACE1(( "ft_var_load_gvar:" + " number of axes in `gvar' and `cvar'\n" )); + FT_TRACE1(( " table are different\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } @@ -1558,7 +1634,7 @@ goto Exit; /* offsets (one more offset than glyphs, to mark size of last) */ - if ( FT_NEW_ARRAY( blend->glyphoffsets, gvar_head.glyphCount + 1 ) ) + if ( FT_QNEW_ARRAY( blend->glyphoffsets, gvar_head.glyphCount + 1 ) ) goto Fail2; if ( gvar_head.flags & 1 ) @@ -1637,8 +1713,8 @@ goto Fail; } - if ( FT_NEW_ARRAY( blend->tuplecoords, - gvar_head.axisCount * gvar_head.globalCoordCount ) ) + if ( FT_QNEW_ARRAY( blend->tuplecoords, + gvar_head.axisCount * gvar_head.globalCoordCount ) ) goto Fail2; for ( i = 0; i < gvar_head.globalCoordCount; i++ ) @@ -1841,25 +1917,22 @@ FT_TRACE5(( " %d: %.5f\n", i, coord / 65536.0 )); if ( coord > a->maximum || coord < a->minimum ) { - FT_TRACE1(( - "ft_var_to_normalized: design coordinate %.5f\n" - " is out of range [%.5f;%.5f]; clamping\n", - coord / 65536.0, - a->minimum / 65536.0, - a->maximum / 65536.0 )); - - if ( coord > a->maximum ) - coord = a->maximum; - else - coord = a->minimum; + FT_TRACE1(( "ft_var_to_normalized: design coordinate %.5f\n", + coord / 65536.0 )); + FT_TRACE1(( " is out of range [%.5f;%.5f];" + " clamping\n", + a->minimum / 65536.0, + a->maximum / 65536.0 )); } - if ( coord < a->def ) - normalized[i] = -FT_DivFix( SUB_LONG( coord, a->def ), - SUB_LONG( a->minimum, a->def ) ); - else if ( coord > a->def ) - normalized[i] = FT_DivFix( SUB_LONG( coord, a->def ), + if ( coord > a->def ) + normalized[i] = coord >= a->maximum ? 0x10000L : + FT_DivFix( SUB_LONG( coord, a->def ), SUB_LONG( a->maximum, a->def ) ); + else if ( coord < a->def ) + normalized[i] = coord <= a->minimum ? -0x10000L : + FT_DivFix( SUB_LONG( coord, a->def ), + SUB_LONG( a->def, a->minimum ) ); else normalized[i] = 0; } @@ -2049,7 +2122,7 @@ FT_Var_Axis* a; FT_Fixed* c; FT_Var_Named_Style* ns; - GX_FVar_Head fvar_head; + GX_FVar_Head fvar_head = { 0, 0, 0, 0, 0, 0 }; FT_Bool usePsName = 0; FT_UInt num_instances; FT_UInt num_axes; @@ -2115,8 +2188,8 @@ if ( FT_SET_ERROR( face->goto_table( face, TTAG_CFF2, stream, &table_len ) ) ) { - FT_TRACE1(( "\n" - "TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n" )); + FT_TRACE1(( "\n" )); + FT_TRACE1(( "TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n" )); goto Exit; } } @@ -2544,17 +2617,17 @@ num_coords = mmvar->num_axis; } - FT_TRACE5(( "TT_Set_MM_Blend:\n" - " normalized design coordinates:\n" )); + FT_TRACE5(( "TT_Set_MM_Blend:\n" )); + FT_TRACE5(( " normalized design coordinates:\n" )); for ( i = 0; i < num_coords; i++ ) { FT_TRACE5(( " %.5f\n", coords[i] / 65536.0 )); if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) { - FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n" - " is out of range [-1;1]\n", + FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n", coords[i] / 65536.0 )); + FT_TRACE1(( " is out of range [-1;1]\n" )); error = FT_THROW( Invalid_Argument ); goto Exit; } @@ -2652,9 +2725,10 @@ } blend->num_axis = mmvar->num_axis; - FT_MEM_COPY( blend->normalizedcoords, - coords, - num_coords * sizeof ( FT_Fixed ) ); + if ( coords ) + FT_MEM_COPY( blend->normalizedcoords, + coords, + num_coords * sizeof ( FT_Fixed ) ); if ( set_design_coords ) ft_var_to_design( face, @@ -2672,7 +2746,6 @@ /* The cvt table has been loaded already; every time we change the */ /* blend we may need to reload and remodify the cvt table. */ FT_FREE( face->cvt ); - face->cvt = NULL; error = tt_face_load_cvt( face, face->root.stream ); break; @@ -2691,7 +2764,6 @@ /* enforce recomputation of the PostScript name; */ FT_FREE( face->postscript_name ); - face->postscript_name = NULL; Exit: return error; @@ -2952,8 +3024,8 @@ if ( !face->blend->avar_loaded ) ft_var_load_avar( face ); - FT_TRACE5(( "TT_Set_Var_Design:\n" - " normalized design coordinates:\n" )); + FT_TRACE5(( "TT_Set_Var_Design:\n" )); + FT_TRACE5(( " normalized design coordinates:\n" )); ft_var_to_normalized( face, num_coords, blend->coords, normalized ); error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 ); @@ -3152,6 +3224,8 @@ /*************************************************************************/ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + static FT_Error tt_cvt_ready_iterator( FT_ListNode node, void* user ) @@ -3166,6 +3240,9 @@ return FT_Err_Ok; } +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + /************************************************************************** * @@ -3194,6 +3271,8 @@ tt_face_vary_cvt( TT_Face face, FT_Stream stream ) { +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + FT_Error error; FT_Memory memory = stream->memory; @@ -3229,16 +3308,16 @@ if ( !blend ) { - FT_TRACE2(( "\n" - "tt_face_vary_cvt: no blend specified\n" )); + FT_TRACE2(( "\n" )); + FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); error = FT_Err_Ok; goto Exit; } if ( !face->cvt ) { - FT_TRACE2(( "\n" - "tt_face_vary_cvt: no `cvt ' table\n" )); + FT_TRACE2(( "\n" )); + FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); error = FT_Err_Ok; goto Exit; } @@ -3388,6 +3467,7 @@ } else { + localpoints = NULL; points = sharedpoints; point_count = spoint_count; } @@ -3397,9 +3477,7 @@ point_count == 0 ? face->cvt_size : point_count ); - if ( !points || - !deltas || - ( localpoints == ALL_POINTS && point_count != face->cvt_size ) ) + if ( !points || !deltas ) ; /* failure, ignore it */ else if ( localpoints == ALL_POINTS ) @@ -3514,6 +3592,16 @@ NULL ); return error; + +#else /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader (specification) * - * Copyright (C) 2004-2020 by + * Copyright (C) 2004-2022 by * David Turner, Robert Wilhelm, Werner Lemberg and George Williams. * * This file is part of the FreeType project, and may only be used, @@ -106,9 +106,9 @@ typedef struct GX_DeltaSetIdxMapRec_ { - FT_UInt mapCount; - FT_UInt* outerIndex; /* indices to item var data */ - FT_UInt* innerIndex; /* indices to delta set */ + FT_ULong mapCount; + FT_UInt* outerIndex; /* indices to item var data */ + FT_UInt* innerIndex; /* indices to delta set */ } GX_DeltaSetIdxMapRec, *GX_DeltaSetIdxMap; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -251,6 +251,14 @@ FT_FREE( exec->stack ); exec->stackSize = 0; + /* free glyf cvt working area */ + FT_FREE( exec->glyfCvt ); + exec->glyfCvtSize = 0; + + /* free glyf storage working area */ + FT_FREE( exec->glyfStorage ); + exec->glyfStoreSize = 0; + /* free call stack */ FT_FREE( exec->callStack ); exec->callSize = 0; @@ -270,64 +278,6 @@ /************************************************************************** * * @Function: - * Init_Context - * - * @Description: - * Initializes a context object. - * - * @Input: - * memory :: - * A handle to the parent memory object. - * - * @InOut: - * exec :: - * A handle to the target execution context. - * - * @Return: - * FreeType error code. 0 means success. - */ - static FT_Error - Init_Context( TT_ExecContext exec, - FT_Memory memory ) - { - FT_Error error; - - - FT_TRACE1(( "Init_Context: new object at %p\n", (void *)exec )); - - exec->memory = memory; - exec->callSize = 32; - - if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) ) - goto Fail_Memory; - - /* all values in the context are set to 0 already, but this is */ - /* here as a remainder */ - exec->maxPoints = 0; - exec->maxContours = 0; - - exec->stackSize = 0; - exec->glyphSize = 0; - - exec->stack = NULL; - exec->glyphIns = NULL; - - exec->face = NULL; - exec->size = NULL; - - return FT_Err_Ok; - - Fail_Memory: - FT_ERROR(( "Init_Context: not enough memory for %p\n", (void *)exec )); - TT_Done_Context( exec ); - - return error; - } - - - /************************************************************************** - * - * @Function: * Update_Max * * @Description: @@ -367,7 +317,7 @@ if ( *size < new_max ) { - if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) ) + if ( FT_QREALLOC( *pbuff, *size * multiplier, new_max * multiplier ) ) return error; *size = new_max; } @@ -400,6 +350,8 @@ * * @Note: * Only the glyph loader and debugger should call this function. + * + * Note that not all members of `TT_ExecContext` get initialized. */ FT_LOCAL_DEF( FT_Error ) TT_Load_Context( TT_ExecContext exec, @@ -464,13 +416,13 @@ if ( error ) return error; - tmp = exec->glyphSize; + tmp = (FT_ULong)exec->glyphSize; error = Update_Max( exec->memory, &tmp, sizeof ( FT_Byte ), (void*)&exec->glyphIns, maxp->maxSizeOfInstructions ); - exec->glyphSize = (FT_UShort)tmp; + exec->glyphSize = (FT_UInt)tmp; if ( error ) return error; @@ -564,6 +516,14 @@ exec->GS.round_state = 1; exec->GS.loop = 1; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + exec->iup_called = FALSE; +#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + exec->iupx_called = FALSE; + exec->iupy_called = FALSE; +#endif + /* some glyphs leave something on the stack. so we clean it */ /* before a new execution. */ exec->top = 0; @@ -609,19 +569,19 @@ memory = driver->root.root.memory; - /* allocate object */ + /* allocate object and zero everything inside */ if ( FT_NEW( exec ) ) goto Fail; - /* initialize it; in case of error this deallocates `exec' too */ - error = Init_Context( exec, memory ); - if ( error ) - goto Fail; + /* create callStack here, other allocations delayed */ + exec->memory = memory; + exec->callSize = 32; - return exec; + if ( FT_QNEW_ARRAY( exec->callStack, exec->callSize ) ) + FT_FREE( exec ); Fail: - return NULL; + return exec; } @@ -1572,11 +1532,36 @@ } + static void + Modify_CVT_Check( TT_ExecContext exc ) + { + /* TT_RunIns sets origCvt and restores cvt to origCvt when done. */ + if ( exc->iniRange == tt_coderange_glyph && + exc->cvt == exc->origCvt ) + { + exc->error = Update_Max( exc->memory, + &exc->glyfCvtSize, + sizeof ( FT_Long ), + (void*)&exc->glyfCvt, + exc->cvtSize ); + if ( exc->error ) + return; + + FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize ); + exc->cvt = exc->glyfCvt; + } + } + + FT_CALLBACK_DEF( void ) Write_CVT( TT_ExecContext exc, FT_ULong idx, FT_F26Dot6 value ) { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[idx] = value; } @@ -1586,6 +1571,10 @@ FT_ULong idx, FT_F26Dot6 value ) { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) ); } @@ -1595,6 +1584,10 @@ FT_ULong idx, FT_F26Dot6 value ) { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[idx] = ADD_LONG( exc->cvt[idx], value ); } @@ -1604,6 +1597,10 @@ FT_ULong idx, FT_F26Dot6 value ) { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[idx] = ADD_LONG( exc->cvt[idx], FT_DivFix( value, Current_Ratio( exc ) ) ); } @@ -3125,7 +3122,30 @@ ARRAY_BOUND_ERROR; } else + { + /* TT_RunIns sets origStorage and restores storage to origStorage */ + /* when done. */ + if ( exc->iniRange == tt_coderange_glyph && + exc->storage == exc->origStorage ) + { + FT_ULong tmp = (FT_ULong)exc->glyfStoreSize; + + + exc->error = Update_Max( exc->memory, + &tmp, + sizeof ( FT_Long ), + (void*)&exc->glyfStorage, + exc->storeSize ); + exc->glyfStoreSize = (FT_UShort)tmp; + if ( exc->error ) + return; + + FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize ); + exc->storage = exc->glyfStorage; + } + exc->storage[I] = args[1]; + } } @@ -3525,7 +3545,7 @@ return; } - exc->IP += args[0]; + exc->IP = ADD_LONG( exc->IP, args[0] ); if ( exc->IP < 0 || ( exc->callTop > 0 && exc->IP > exc->callStack[exc->callTop - 1].Def->end ) ) @@ -3697,7 +3717,7 @@ /* FDEF is only allowed in `prep' or `fpgm' */ - if ( exc->curRange == tt_coderange_glyph ) + if ( exc->iniRange == tt_coderange_glyph ) { exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); return; @@ -3771,7 +3791,7 @@ if ( opcode_pointer[i] == opcode_size[i] ) { - FT_TRACE6(( "sph: Function %d, opcode ptrn: %d, %s %s\n", + FT_TRACE6(( "sph: Function %d, opcode ptrn: %ld, %s %s\n", i, n, exc->face->root.family_name, exc->face->root.style_name )); @@ -4133,7 +4153,7 @@ /* we enable IDEF only in `prep' or `fpgm' */ - if ( exc->curRange == tt_coderange_glyph ) + if ( exc->iniRange == tt_coderange_glyph ) { exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); return; @@ -4362,7 +4382,7 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ + C = B; /* counter-clockwise rotation */ B = A; A = NEG_LONG( C ); } @@ -4991,9 +5011,9 @@ #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */ - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - FT_ABS( D ) == 64 ) + if ( SUBPIXEL_HINTING_INFINALITY && + exc->ignore_x_mode && + ( D < 0 ? NEG_LONG( D ) : D ) == 64 ) D += 1; #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ @@ -5050,7 +5070,7 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ + C = B; /* counter-clockwise rotation */ B = A; A = NEG_LONG( C ); } @@ -5074,7 +5094,7 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ + C = B; /* counter-clockwise rotation */ B = A; A = NEG_LONG( C ); } @@ -5248,16 +5268,21 @@ } } - exc->GS.instruct_control &= ~(FT_Byte)Kf; - exc->GS.instruct_control |= (FT_Byte)L; + /* INSTCTRL should only be used in the CVT program */ + if ( exc->iniRange == tt_coderange_cvt ) + { + exc->GS.instruct_control &= ~(FT_Byte)Kf; + exc->GS.instruct_control |= (FT_Byte)L; + } - if ( K == 3 ) + /* except to change the subpixel flags temporarily */ + else if ( exc->iniRange == tt_coderange_glyph && K == 3 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* INSTCTRL modifying flag 3 also has an effect */ /* outside of the CVT program */ if ( SUBPIXEL_HINTING_INFINALITY ) - exc->ignore_x_mode = FT_BOOL( L == 4 ); + exc->ignore_x_mode = !FT_BOOL( L == 4 ); #endif #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL @@ -5268,6 +5293,8 @@ exc->backward_compatibility = !FT_BOOL( L == 4 ); #endif } + else if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); } @@ -7743,35 +7770,6 @@ #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - exc->iup_called = FALSE; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - /* - * Toggle backward compatibility according to what font wants, except - * when - * - * 1) we have a `tricky' font that heavily relies on the interpreter to - * render glyphs correctly, for example DFKai-SB, or - * 2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested. - * - * In those cases, backward compatibility needs to be turned off to get - * correct rendering. The rendering is then completely up to the - * font's programming. - * - */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->subpixel_hinting_lean && - !FT_IS_TRICKY( &exc->face->root ) ) - exc->backward_compatibility = !( exc->GS.instruct_control & 4 ); - else - exc->backward_compatibility = FALSE; - - exc->iupx_called = FALSE; - exc->iupy_called = FALSE; -#endif - /* We restrict the number of twilight points to a reasonable, */ /* heuristic value to avoid slow execution of malformed bytecode. */ num_twilight_points = FT_MAX( 30, @@ -7781,8 +7779,8 @@ if ( num_twilight_points > 0xFFFFU ) num_twilight_points = 0xFFFFU; - FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" - " from %d to the more reasonable value %ld\n", + FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" )); + FT_TRACE5(( " from %d to the more reasonable value %ld\n", exc->twilight.n_points, num_twilight_points )); exc->twilight.n_points = (FT_UShort)num_twilight_points; @@ -7842,6 +7840,10 @@ exc->func_move_cvt = Move_CVT; } + exc->origCvt = exc->cvt; + exc->origStorage = exc->storage; + exc->iniRange = exc->curRange; + Compute_Funcs( exc ); Compute_Round( exc, (FT_Byte)exc->GS.round_state ); @@ -7850,6 +7852,7 @@ exc->opcode = exc->code[exc->IP]; #ifdef FT_DEBUG_LEVEL_TRACE + if ( ft_trace_levels[trace_ttinterp] >= 6 ) { FT_Long cnt = FT_MIN( 8, exc->top ); FT_Long n; @@ -8566,8 +8569,10 @@ /* increment instruction counter and check if we didn't */ /* run this program for too long (e.g. infinite loops). */ - if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) - return FT_THROW( Execution_Too_Long ); + if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) { + exc->error = FT_THROW( Execution_Too_Long ); + goto LErrorLabel_; + } LSuiteLabel_: if ( exc->IP >= exc->codeSize ) @@ -8586,6 +8591,10 @@ FT_TRACE4(( " %ld instruction%s executed\n", ins_counter, ins_counter == 1 ? "" : "s" )); + + exc->cvt = exc->origCvt; + exc->storage = exc->origStorage; + return FT_Err_Ok; LErrorCodeOverflow_: @@ -8595,6 +8604,9 @@ if ( exc->error && !exc->instruction_trap ) FT_TRACE1(( " The interpreter returned error 0x%x\n", exc->error )); + exc->cvt = exc->origCvt; + exc->storage = exc->origStorage; + return exc->error; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -144,37 +144,41 @@ * * The main structure for the interpreter which collects all necessary * variables and states. + * + * Members that are initialized by `TT_Load_Context` are marked with '!'. + * Members that are initialized by `TT_Run_Context` are marked with '@'. */ typedef struct TT_ExecContextRec_ { - TT_Face face; - TT_Size size; + TT_Face face; /* ! */ + TT_Size size; /* ! */ FT_Memory memory; /* instructions state */ FT_Error error; /* last execution error */ - FT_Long top; /* top of exec. stack */ + FT_Long top; /* @ top of exec. stack */ - FT_Long stackSize; /* size of exec. stack */ - FT_Long* stack; /* current exec. stack */ + FT_Long stackSize; /* ! size of exec. stack */ + FT_Long* stack; /* ! current exec. stack */ FT_Long args; - FT_Long new_top; /* new top after exec. */ + FT_Long new_top; /* new top after exec. */ + + TT_GlyphZoneRec zp0, /* @! zone records */ + zp1, /* @! */ + zp2, /* @! */ + pts, /* ! */ + twilight; /* ! */ - TT_GlyphZoneRec zp0, /* zone records */ - zp1, - zp2, - pts, - twilight; - - FT_Long pointSize; /* in 26.6 format */ - FT_Size_Metrics metrics; - TT_Size_Metrics tt_metrics; /* size metrics */ + FT_Long pointSize; /* ! in 26.6 format */ + FT_Size_Metrics metrics; /* ! */ + TT_Size_Metrics tt_metrics; /* ! size metrics */ - TT_GraphicsState GS; /* current graphics state */ + TT_GraphicsState GS; /* !@ current graphics state */ + FT_Int iniRange; /* initial code range number */ FT_Int curRange; /* current code range number */ FT_Byte* code; /* current code range */ FT_Long IP; /* current instruction pointer */ @@ -185,43 +189,49 @@ FT_Bool step_ins; /* true if the interpreter must */ /* increment IP after ins. exec */ - FT_ULong cvtSize; - FT_Long* cvt; - - FT_UInt glyphSize; /* glyph instructions buffer size */ - FT_Byte* glyphIns; /* glyph instructions buffer */ - - FT_UInt numFDefs; /* number of function defs */ - FT_UInt maxFDefs; /* maximum number of function defs */ - TT_DefArray FDefs; /* table of FDefs entries */ - - FT_UInt numIDefs; /* number of instruction defs */ - FT_UInt maxIDefs; /* maximum number of ins defs */ - TT_DefArray IDefs; /* table of IDefs entries */ - - FT_UInt maxFunc; /* maximum function index */ - FT_UInt maxIns; /* maximum instruction index */ - - FT_Int callTop, /* top of call stack during execution */ - callSize; /* size of call stack */ - TT_CallStack callStack; /* call stack */ + FT_ULong cvtSize; /* ! */ + FT_Long* cvt; /* ! */ + FT_ULong glyfCvtSize; + FT_Long* glyfCvt; /* cvt working copy for glyph */ + FT_Long* origCvt; + + FT_UInt glyphSize; /* ! glyph instructions buffer size */ + FT_Byte* glyphIns; /* ! glyph instructions buffer */ + + FT_UInt numFDefs; /* ! number of function defs */ + FT_UInt maxFDefs; /* ! maximum number of function defs */ + TT_DefArray FDefs; /* table of FDefs entries */ + + FT_UInt numIDefs; /* ! number of instruction defs */ + FT_UInt maxIDefs; /* ! maximum number of ins defs */ + TT_DefArray IDefs; /* table of IDefs entries */ + + FT_UInt maxFunc; /* ! maximum function index */ + FT_UInt maxIns; /* ! maximum instruction index */ + + FT_Int callTop, /* @ top of call stack during execution */ + callSize; /* size of call stack */ + TT_CallStack callStack; /* call stack */ FT_UShort maxPoints; /* capacity of this context's `pts' */ FT_Short maxContours; /* record, expressed in points and */ /* contours. */ - TT_CodeRangeTable codeRangeTable; /* table of valid code ranges */ - /* useful for the debugger */ + TT_CodeRangeTable codeRangeTable; /* ! table of valid code ranges */ + /* useful for the debugger */ - FT_UShort storeSize; /* size of current storage */ - FT_Long* storage; /* storage area */ + FT_UShort storeSize; /* ! size of current storage */ + FT_Long* storage; /* ! storage area */ + FT_UShort glyfStoreSize; + FT_Long* glyfStorage; /* storage working copy for glyph */ + FT_Long* origStorage; FT_F26Dot6 period; /* values used for the */ FT_F26Dot6 phase; /* `SuperRounding' */ FT_F26Dot6 threshold; - FT_Bool instruction_trap; /* If `True', the interpreter will */ - /* exit after each instruction */ + FT_Bool instruction_trap; /* ! If `True', the interpreter */ + /* exits after each instruction */ TT_GraphicsState default_GS; /* graphics state resulting from */ /* the prep program */ @@ -238,7 +248,7 @@ func_dualproj, /* current dual proj. function */ func_freeProj; /* current freedom proj. func */ - TT_Move_Func func_move; /* current point move function */ + TT_Move_Func func_move; /* current point move function */ TT_Move_Func func_move_orig; /* move original position function */ TT_Cur_Ppem_Func func_cur_ppem; /* get current proj. ppem value */ @@ -469,16 +479,15 @@ * TT_New_Context * * @Description: - * Queries the face context for a given font. Note that there is - * now a _single_ execution context in the TrueType driver which is - * shared among faces. + * Create a `TT_ExecContext`. Note that there is now an execution + * context per `TT_Size` that is not shared among faces. * * @Input: - * face :: - * A handle to the source face object. + * driver :: + * A handle to the driver, used for memory allocation. * * @Return: - * A handle to the execution context. Initialized for `face'. + * A handle to a new empty execution context. * * @Note: * Only the glyph loader and debugger should call this function. diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Objects manager (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -140,7 +140,31 @@ return error; } -#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /* + * Fonts embedded in PDFs are made unique by prepending randomization + * prefixes to their names: as defined in Section 5.5.3, 'Font Subsets', + * of the PDF Reference, they consist of 6 uppercase letters followed by + * the `+` sign. For safety, we do not skip prefixes violating this rule. + */ + + static const FT_String* + tt_skip_pdffont_random_tag( const FT_String* name ) + { + unsigned int i; + + + if ( ft_strlen( name ) < 8 || name[6] != '+' ) + return name; + + for ( i = 0; i < 6; i++ ) + if ( !ft_isupper( name[i] ) ) + return name; + + FT_TRACE7(( "name without randomization tag: %s\n", name + 7 )); + return name + 7; + } /* Compare the face with a list of well-known `tricky' fonts. */ @@ -151,7 +175,7 @@ { #define TRICK_NAMES_MAX_CHARACTERS 19 -#define TRICK_NAMES_COUNT 26 +#define TRICK_NAMES_COUNT 20 static const char trick_names[TRICK_NAMES_COUNT] [TRICK_NAMES_MAX_CHARACTERS + 1] = @@ -171,22 +195,28 @@ "DFGirl-W6-WIN-BF", /* dftt-h6.ttf; version 1.00, 1993 */ "DFGothic-EB", /* DynaLab Inc. 1992-1995 */ "DFGyoSho-Lt", /* DynaLab Inc. 1992-1995 */ - "DFHei-Md-HK-BF", /* maybe DynaLab Inc. */ + "DFHei", /* DynaLab Inc. 1992-1995 [DFHei-Bd-WIN-HK-BF] */ + /* covers "DFHei-Md-HK-BF", maybe DynaLab Inc. */ + "DFHSGothic-W5", /* DynaLab Inc. 1992-1995 */ "DFHSMincho-W3", /* DynaLab Inc. 1992-1995 */ "DFHSMincho-W7", /* DynaLab Inc. 1992-1995 */ "DFKaiSho-SB", /* dfkaisb.ttf */ - "DFKaiShu", - "DFKaiShu-Md-HK-BF", /* maybe DynaLab Inc. */ + "DFKaiShu", /* covers "DFKaiShu-Md-HK-BF", maybe DynaLab Inc. */ "DFKai-SB", /* kaiu.ttf; version 3.00, 1998 [DFKaiShu-SB-Estd-BF] */ - "DFMing-Bd-HK-BF", /* maybe DynaLab Inc. */ + + "DFMing", /* DynaLab Inc. 1992-1995 [DFMing-Md-WIN-HK-BF] */ + /* covers "DFMing-Bd-HK-BF", maybe DynaLab Inc. */ + "DLC", /* dftt-m7.ttf; version 1.00, 1993 [DLCMingBold] */ /* dftt-f5.ttf; version 1.00, 1993 [DLCFongSung] */ - "DLCHayMedium", /* dftt-b5.ttf; version 1.00, 1993 */ - "DLCHayBold", /* dftt-b7.ttf; version 1.00, 1993 */ - "DLCKaiMedium", /* dftt-k5.ttf; version 1.00, 1992 */ - "DLCLiShu", /* dftt-l5.ttf; version 1.00, 1992 */ - "DLCRoundBold", /* dftt-r7.ttf; version 1.00, 1993 */ + /* covers following */ + /* "DLCHayMedium", dftt-b5.ttf; version 1.00, 1993 */ + /* "DLCHayBold", dftt-b7.ttf; version 1.00, 1993 */ + /* "DLCKaiMedium", dftt-k5.ttf; version 1.00, 1992 */ + /* "DLCLiShu", dftt-l5.ttf; version 1.00, 1992 */ + /* "DLCRoundBold", dftt-r7.ttf; version 1.00, 1993 */ + "HuaTianKaiTi?", /* htkt2.ttf */ "HuaTianSongTi?", /* htst3.ttf */ "Ming(for ISO10646)", /* hkscsiic.ttf; version 0.12, 2007 [Ming] */ @@ -199,10 +229,12 @@ }; int nn; + const FT_String* name_without_tag; + name_without_tag = tt_skip_pdffont_random_tag( name ); for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) - if ( ft_strstr( name, trick_names[nn] ) ) + if ( ft_strstr( name_without_tag, trick_names[nn] ) ) return TRUE; return FALSE; @@ -277,7 +309,7 @@ tt_check_trickyness_sfnt_ids( TT_Face face ) { #define TRICK_SFNT_IDS_PER_FACE 3 -#define TRICK_SFNT_IDS_NUM_FACES 29 +#define TRICK_SFNT_IDS_NUM_FACES 31 static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] [TRICK_SFNT_IDS_PER_FACE] = { @@ -430,6 +462,16 @@ { 0x00170003UL, 0x00000060UL }, /* cvt */ { 0xDBB4306EUL, 0x000058AAUL }, /* fpgm */ { 0xD643482AUL, 0x00000035UL } /* prep */ + }, + { /* DFHei-Bd-WIN-HK-BF, issue #1087 */ + { 0x1269EB58UL, 0x00000350UL }, /* cvt */ + { 0x5CD5957AUL, 0x00006A4EUL }, /* fpgm */ + { 0xF758323AUL, 0x00000380UL } /* prep */ + }, + { /* DFMing-Md-WIN-HK-BF, issue #1087 */ + { 0x122FEB0BUL, 0x00000350UL }, /* cvt */ + { 0x7F10919AUL, 0x000070A9UL }, /* fpgm */ + { 0x7CD7E7B7UL, 0x0000025CUL } /* prep */ } }; @@ -510,17 +552,27 @@ /* For first, check the face name for quick check. */ if ( face->family_name && tt_check_trickyness_family( face->family_name ) ) + { + FT_TRACE3(( "found as a tricky font" + " by its family name: %s\n", face->family_name )); return TRUE; + } /* Type42 fonts may lack `name' tables, we thus try to identify */ /* tricky fonts by checking the checksums of Type42-persistent */ /* sfnt tables (`cvt', `fpgm', and `prep'). */ if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) ) + { + FT_TRACE3(( "found as a tricky font" + " by its cvt/fpgm/prep table checksum\n" )); return TRUE; + } return FALSE; } +#endif /* TT_USE_BYTECODE_INTERPRETER */ + /* Check whether `.notdef' is the only glyph in the `loca' table. */ static FT_Bool @@ -666,14 +718,17 @@ if ( error ) goto Exit; +#ifdef TT_USE_BYTECODE_INTERPRETER if ( tt_check_trickyness( ttface ) ) ttface->face_flags |= FT_FACE_FLAG_TRICKY; +#endif error = tt_face_load_hdmx( face, stream ); if ( error ) goto Exit; - if ( FT_IS_SCALABLE( ttface ) ) + if ( FT_IS_SCALABLE( ttface ) || + FT_HAS_SBIX( ttface ) ) { #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( !ttface->internal->incremental_interface ) @@ -712,8 +767,8 @@ tt_check_single_notdef( ttface ) ) { FT_TRACE5(( "tt_face_init:" - " Only the `.notdef' glyph has an outline.\n" - " " + " Only the `.notdef' glyph has an outline.\n" )); + FT_TRACE5(( " " " Resetting scalable flag to FALSE.\n" )); ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; @@ -1190,11 +1245,11 @@ /* rescale CVT when needed */ if ( size->cvt_ready < 0 ) { - FT_UInt i; + FT_UShort i; /* all twilight points are originally zero */ - for ( i = 0; i < (FT_UInt)size->twilight.n_points; i++ ) + for ( i = 0; i < size->twilight.n_points; i++ ) { size->twilight.org[i].x = 0; size->twilight.org[i].y = 0; @@ -1203,7 +1258,7 @@ } /* clear storage area */ - for ( i = 0; i < (FT_UInt)size->storage_size; i++ ) + for ( i = 0; i < size->storage_size; i++ ) size->storage[i] = 0; size->GS = tt_default_graphics_state; @@ -1381,6 +1436,8 @@ size->ttmetrics.y_ratio = 0x10000L; } + size->widthp = tt_face_get_device_metrics( face, size_metrics->x_ppem, 0 ); + size->metrics = size_metrics; #ifdef TT_USE_BYTECODE_INTERPRETER diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Objects manager (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -282,6 +282,8 @@ TT_Size_Metrics ttmetrics; + FT_Byte* widthp; /* glyph widths from the hdmx table */ + FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ #ifdef TT_USE_BYTECODE_INTERPRETER diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -98,36 +98,23 @@ goto Exit; } - if ( face->header.Index_To_Loc_Format != 0 ) - { - shift = 2; + shift = face->header.Index_To_Loc_Format != 0 ? 2 : 1; - if ( table_len >= 0x40000L ) - { - FT_TRACE2(( "table too large\n" )); - table_len = 0x3FFFFL; - } - face->num_locations = table_len >> shift; - } - else + if ( table_len > 0x10000UL << shift ) { - shift = 1; - - if ( table_len >= 0x20000L ) - { - FT_TRACE2(( "table too large\n" )); - table_len = 0x1FFFFL; - } - face->num_locations = table_len >> shift; + FT_TRACE2(( "table too large\n" )); + table_len = 0x10000UL << shift; } + face->num_locations = table_len >> shift; + if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) { FT_TRACE2(( "glyph count mismatch! loca: %ld, maxp: %ld\n", face->num_locations - 1, face->root.num_glyphs )); /* we only handle the case where `maxp' gives a larger value */ - if ( face->num_locations <= (FT_ULong)face->root.num_glyphs ) + if ( face->num_locations < (FT_ULong)face->root.num_glyphs + 1 ) { FT_ULong new_loca_len = ( (FT_ULong)face->root.num_glyphs + 1 ) << shift; @@ -237,10 +224,11 @@ if ( pos1 > face->glyf_len ) { FT_TRACE1(( "tt_face_get_location:" - " too large offset (0x%08lx) found for glyph index %d,\n" - " " + " too large offset (0x%08lx) found for glyph index %d,\n", + pos1, gindex )); + FT_TRACE1(( " " " exceeding the end of `glyf' table (0x%08lx)\n", - pos1, gindex, face->glyf_len )); + face->glyf_len )); *asize = 0; return 0; } @@ -251,19 +239,21 @@ if ( gindex == face->num_locations - 2 ) { FT_TRACE1(( "tt_face_get_location:" - " too large size (%ld bytes) found for glyph index %d,\n" - " " + " too large size (%ld bytes) found for glyph index %d,\n", + pos2 - pos1, gindex )); + FT_TRACE1(( " " " truncating at the end of `glyf' table to %ld bytes\n", - pos2 - pos1, gindex, face->glyf_len - pos1 )); + face->glyf_len - pos1 )); pos2 = face->glyf_len; } else { FT_TRACE1(( "tt_face_get_location:" - " too large offset (0x%08lx) found for glyph index %d,\n" - " " + " too large offset (0x%08lx) found for glyph index %d,\n", + pos2, gindex + 1 )); + FT_TRACE1(( " " " exceeding the end of `glyf' table (0x%08lx)\n", - pos2, gindex + 1, face->glyf_len )); + face->glyf_len )); *asize = 0; return 0; } @@ -344,7 +334,7 @@ face->cvt_size = table_len / 2; - if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) + if ( FT_QNEW_ARRAY( face->cvt, face->cvt_size ) ) goto Exit; if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) @@ -508,6 +498,14 @@ } + FT_COMPARE_DEF( int ) + compare_ppem( const void* a, + const void* b ) + { + return **(FT_Byte**)a - **(FT_Byte**)b; + } + + /************************************************************************** * * @Function: @@ -557,12 +555,6 @@ num_records = FT_NEXT_USHORT( p ); record_size = FT_NEXT_ULONG( p ); - /* The maximum number of bytes in an hdmx device record is the */ - /* maximum number of glyphs + 2; this is 0xFFFF + 2, thus */ - /* explaining why `record_size' is a long (which we read as */ - /* unsigned long for convenience). In practice, two bytes are */ - /* sufficient to hold the size value. */ - /* */ /* There are at least two fonts, HANNOM-A and HANNOM-B version */ /* 2.0 (2005), which get this wrong: The upper two bytes of */ /* the size value are set to 0xFF instead of 0x00. We catch */ @@ -571,32 +563,46 @@ if ( record_size >= 0xFFFF0000UL ) record_size &= 0xFFFFU; + FT_TRACE2(( "Hdmx " )); + /* The limit for `num_records' is a heuristic value. */ - if ( num_records > 255 || - ( num_records > 0 && - ( record_size > 0x10001L || - record_size < 4 ) ) ) + if ( num_records > 255 || num_records == 0 ) { - error = FT_THROW( Invalid_File_Format ); + FT_TRACE2(( "with unreasonable %u records rejected\n", num_records )); + goto Fail; + } + + /* Out-of-spec tables are rejected. The record size must be */ + /* equal to the number of glyphs + 2 + 32-bit padding. */ + if ( (FT_Long)record_size != ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) ) + { + FT_TRACE2(( "with record size off by %ld bytes rejected\n", + (FT_Long)record_size - + ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) )); goto Fail; } - if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) + if ( FT_QNEW_ARRAY( face->hdmx_records, num_records ) ) goto Fail; for ( nn = 0; nn < num_records; nn++ ) { if ( p + record_size > limit ) break; - - face->hdmx_record_sizes[nn] = p[0]; - p += record_size; + face->hdmx_records[nn] = p; + p += record_size; } + /* The records must be already sorted by ppem but it does not */ + /* hurt to make sure so that the binary search works later. */ + ft_qsort( face->hdmx_records, nn, sizeof ( FT_Byte* ), compare_ppem ); + face->hdmx_record_count = nn; face->hdmx_table_size = table_size; face->hdmx_record_size = record_size; + FT_TRACE2(( "%ux%lu loaded\n", num_records, record_size )); + Exit: return error; @@ -614,7 +620,7 @@ FT_Memory memory = stream->memory; - FT_FREE( face->hdmx_record_sizes ); + FT_FREE( face->hdmx_records ); FT_FRAME_RELEASE( face->hdmx_table ); } @@ -622,27 +628,34 @@ /************************************************************************** * * Return the advance width table for a given pixel size if it is found - * in the font's `hdmx' table (if any). + * in the font's `hdmx' table (if any). The records must be sorted for + * the binary search to work properly. */ FT_LOCAL_DEF( FT_Byte* ) tt_face_get_device_metrics( TT_Face face, FT_UInt ppem, FT_UInt gindex ) { - FT_UInt nn; - FT_Byte* result = NULL; - FT_ULong record_size = face->hdmx_record_size; - FT_Byte* record = FT_OFFSET( face->hdmx_table, 8 ); + FT_UInt min = 0; + FT_UInt max = face->hdmx_record_count; + FT_UInt mid; + FT_Byte* result = NULL; + + while ( min < max ) + { + mid = ( min + max ) >> 1; - for ( nn = 0; nn < face->hdmx_record_count; nn++ ) - if ( face->hdmx_record_sizes[nn] == ppem ) + if ( face->hdmx_records[mid][0] > ppem ) + max = mid; + else if ( face->hdmx_records[mid][0] < ppem ) + min = mid + 1; + else { - gindex += 2; - if ( gindex < record_size ) - result = record + nn * record_size + gindex; + result = face->hdmx_records[mid] + 2 + gindex; break; } + } return result; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType Subpixel Hinting. * - * Copyright (C) 2010-2020 by + * Copyright (C) 2010-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -315,7 +315,7 @@ static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] = { - /* fix vwxyz thinness*/ + /* fix vwxyz thinness */ { "Consolas", 0, "", 0 }, /* Fix thin middle stems */ { "Core MS Legacy Fonts", 0, "Regular", 0 }, @@ -891,12 +891,12 @@ #define TWEAK_RULES( x ) \ if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ x##_Rules, x##_RULES_SIZE ) ) \ - loader->exec->sph_tweak_flags |= SPH_TWEAK_##x; + loader->exec->sph_tweak_flags |= SPH_TWEAK_##x #define TWEAK_RULES_EXCEPTIONS( x ) \ if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \ - loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x; + loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x FT_LOCAL_DEF( void ) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * TrueType Subpixel Hinting. * - * Copyright (C) 2010-2020 by + * Copyright (C) 2010-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -83,7 +83,7 @@ /* compare two kerning pairs */ - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_kern_pairs( const void* a, const void* b ) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 driver interface (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * High-level Type 1 driver interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -79,7 +79,7 @@ /* For ordinary fonts get the character data stored in the face record. */ { char_string->pointer = type1->charstrings[glyph_index]; - char_string->length = (FT_Int)type1->charstrings_len[glyph_index]; + char_string->length = type1->charstrings_len[glyph_index]; } if ( !error ) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1load.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1load.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1load.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1load.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 font loader (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -117,6 +117,9 @@ goto Exit; blend->num_default_design_vector = 0; + blend->weight_vector = NULL; + blend->default_weight_vector = NULL; + blend->design_pos[0] = NULL; face->blend = blend; } @@ -130,14 +133,11 @@ /* allocate the blend `private' and `font_info' dictionaries */ - if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || - FT_NEW_ARRAY( blend->privates [1], num_designs ) || - FT_NEW_ARRAY( blend->bboxes [1], num_designs ) || - FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) + if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || + FT_NEW_ARRAY( blend->privates [1], num_designs ) || + FT_NEW_ARRAY( blend->bboxes [1], num_designs ) ) goto Exit; - blend->default_weight_vector = blend->weight_vector + num_designs; - blend->font_infos[0] = &face->type1.font_info; blend->privates [0] = &face->type1.private_dict; blend->bboxes [0] = &face->type1.font_bbox; @@ -164,21 +164,6 @@ blend->num_axis = num_axis; } - /* allocate the blend design pos table if needed */ - num_designs = blend->num_designs; - num_axis = blend->num_axis; - if ( num_designs && num_axis && blend->design_pos[0] == 0 ) - { - FT_UInt n; - - - if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) - goto Exit; - - for ( n = 1; n < num_designs; n++ ) - blend->design_pos[n] = blend->design_pos[0] + num_axis * n; - } - Exit: return error; @@ -580,7 +565,7 @@ { FT_Error error; PS_Blend blend = face->blend; - FT_UInt n, p; + FT_UInt n; FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; @@ -599,7 +584,7 @@ PS_DesignMap map = blend->design_map + n; FT_Long* designs = map->design_points; FT_Fixed* blends = map->blend_points; - FT_Int before = -1, after = -1; + FT_Int p, before = -1, after = -1; /* use a default value if we don't have a coordinate */ @@ -608,7 +593,7 @@ else design = ( designs[map->num_points - 1] - designs[0] ) / 2; - for ( p = 0; p < (FT_UInt)map->num_points; p++ ) + for ( p = 0; p < (FT_Int)map->num_points; p++ ) { FT_Long p_design = designs[p]; @@ -622,11 +607,11 @@ if ( design < p_design ) { - after = (FT_Int)p; + after = p; break; } - before = (FT_Int)p; + before = p; } /* now interpolate if necessary */ @@ -851,7 +836,7 @@ FT_FREE( name ); } - if ( FT_ALLOC( blend->axis_names[n], len + 1 ) ) + if ( FT_QALLOC( blend->axis_names[n], len + 1 ) ) goto Exit; name = (FT_Byte*)blend->axis_names[n]; @@ -872,12 +857,14 @@ { T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; FT_Int num_designs; - FT_Int num_axis; - T1_Parser parser = &loader->parser; + FT_Int num_axis = 0; /* make compiler happy */ + T1_Parser parser = &loader->parser; + FT_Memory memory = face->root.memory; + FT_Error error = FT_Err_Ok; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; - FT_Error error = FT_Err_Ok; - PS_Blend blend; + design_pos[0] = NULL; /* get the array of design tokens -- compute number of designs */ T1_ToTokenArray( parser, design_tokens, @@ -899,12 +886,10 @@ { FT_Byte* old_cursor = parser->root.cursor; FT_Byte* old_limit = parser->root.limit; - FT_Int n; + FT_Int n, nn; + PS_Blend blend; - blend = face->blend; - num_axis = 0; /* make compiler happy */ - FT_TRACE4(( " [" )); for ( n = 0; n < num_designs; n++ ) @@ -937,7 +922,13 @@ (FT_UInt)num_axis ); if ( error ) goto Exit; - blend = face->blend; + + /* allocate a blend design pos table */ + if ( FT_QNEW_ARRAY( design_pos[0], num_designs * num_axis ) ) + goto Exit; + + for ( nn = 1; nn < num_designs; nn++ ) + design_pos[nn] = design_pos[0] + num_axis * nn; } else if ( n_axis != num_axis ) { @@ -955,8 +946,8 @@ parser->root.cursor = token2->start; parser->root.limit = token2->limit; - blend->design_pos[n][axis] = T1_ToFixed( parser, 0 ); - FT_TRACE4(( " %f", (double)blend->design_pos[n][axis] / 65536 )); + design_pos[n][axis] = T1_ToFixed( parser, 0 ); + FT_TRACE4(( " %f", (double)design_pos[n][axis] / 65536 )); } FT_TRACE4(( "]" )) ; } @@ -965,9 +956,21 @@ loader->parser.root.cursor = old_cursor; loader->parser.root.limit = old_limit; + + /* a valid BlendDesignPosition has been parsed */ + blend = face->blend; + if ( blend->design_pos[0] ) + FT_FREE( blend->design_pos[0] ); + + for ( n = 0; n < num_designs; n++ ) + { + blend->design_pos[n] = design_pos[n]; + design_pos[n] = NULL; + } } Exit: + FT_FREE( design_pos[0] ); loader->parser.root.error = error; } @@ -1044,7 +1047,7 @@ } /* allocate design map data */ - if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) ) + if ( FT_QNEW_ARRAY( map->design_points, num_points * 2 ) ) goto Exit; map->blend_points = map->design_points + num_points; map->num_points = (FT_Byte)num_points; @@ -1088,6 +1091,7 @@ T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; FT_Int num_designs; FT_Error error = FT_Err_Ok; + FT_Memory memory = face->root.memory; T1_Parser parser = &loader->parser; PS_Blend blend = face->blend; T1_Token token; @@ -1122,13 +1126,19 @@ else if ( blend->num_designs != (FT_UInt)num_designs ) { FT_ERROR(( "parse_weight_vector:" - " /BlendDesignPosition and /WeightVector have\n" - " " + " /BlendDesignPosition and /WeightVector have\n" )); + FT_ERROR(( " " " different number of elements\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } + if ( !blend->weight_vector ) + if ( FT_QNEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) + goto Exit; + + blend->default_weight_vector = blend->weight_vector + num_designs; + old_cursor = parser->root.cursor; old_limit = parser->root.limit; @@ -1307,9 +1317,9 @@ else { FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'" - " which is not valid at this point\n" - " (probably due to missing keywords)\n", + " which is not valid at this point\n", field->ident )); + FT_TRACE1(( " (probably due to missing keywords)\n" )); error = FT_Err_Ok; } @@ -1520,8 +1530,8 @@ /* we use a T1_Table to store our charnames */ loader->num_chars = encode->num_chars = array_size; - if ( FT_NEW_ARRAY( encode->char_index, array_size ) || - FT_NEW_ARRAY( encode->char_name, array_size ) || + if ( FT_QNEW_ARRAY( encode->char_index, array_size ) || + FT_QNEW_ARRAY( encode->char_name, array_size ) || FT_SET_ERROR( psaux->ps_table_funcs->init( char_table, array_size, memory ) ) ) { @@ -1762,7 +1772,7 @@ if ( !loader->subrs_hash ) { - if ( FT_NEW( loader->subrs_hash ) ) + if ( FT_QNEW( loader->subrs_hash ) ) goto Fail; error = ft_hash_num_init( loader->subrs_hash, memory ); @@ -1858,7 +1868,7 @@ } /* t1_decrypt() shouldn't write to base -- make temporary copy */ - if ( FT_ALLOC( temp, size ) ) + if ( FT_QALLOC( temp, size ) ) goto Fail; FT_MEM_COPY( temp, base, size ); psaux->t1_decrypt( temp, size, 4330 ); @@ -2068,7 +2078,7 @@ } /* t1_decrypt() shouldn't write to base -- make temporary copy */ - if ( FT_ALLOC( temp, size ) ) + if ( FT_QALLOC( temp, size ) ) goto Fail; FT_MEM_COPY( temp, base, size ); psaux->t1_decrypt( temp, size, 4330 ); @@ -2578,7 +2588,15 @@ ( !face->blend->num_designs || !face->blend->num_axis ) ) T1_Done_Blend( face ); - /* another safety check */ + /* the font may have no valid WeightVector */ + if ( face->blend && !face->blend->weight_vector ) + T1_Done_Blend( face ); + + /* the font may have no valid BlendDesignPositions */ + if ( face->blend && !face->blend->design_pos[0] ) + T1_Done_Blend( face ); + + /* the font may have no valid BlendDesignMap */ if ( face->blend ) { FT_UInt i; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1load.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1load.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1load.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1load.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 font loader (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 objects manager (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -116,11 +116,15 @@ T1_Size_Request( FT_Size t1size, /* T1_Size */ FT_Size_Request req ) { + FT_Error error; + T1_Size size = (T1_Size)t1size; PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); - FT_Request_Metrics( size->root.face, req ); + error = FT_Request_Metrics( size->root.face, req ); + if ( error ) + goto Exit; if ( funcs ) funcs->set_scale( (PSH_Globals)t1size->internal->module_data, @@ -128,7 +132,8 @@ size->root.metrics.y_scale, 0, 0 ); - return FT_Err_Ok; + Exit: + return error; } @@ -217,7 +222,6 @@ { FT_FREE( face->buildchar ); - face->buildchar = NULL; face->len_buildchar = 0; } @@ -598,11 +602,7 @@ /* set default property values, cf. `ftt1drv.h' */ -#ifdef T1_CONFIG_OPTION_OLD_ENGINE - driver->hinting_engine = FT_HINTING_FREETYPE; -#else driver->hinting_engine = FT_HINTING_ADOBE; -#endif driver->no_stem_darkening = TRUE; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 objects manager (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 parser (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -221,7 +221,7 @@ else { /* read segment in memory -- this is clumsy, but so does the format */ - if ( FT_ALLOC( parser->base_dict, size ) || + if ( FT_QALLOC( parser->base_dict, size ) || FT_STREAM_READ( parser->base_dict, size ) ) goto Exit; parser->base_len = size; @@ -302,8 +302,8 @@ goto Fail; } - if ( FT_STREAM_SEEK( start_pos ) || - FT_ALLOC( parser->private_dict, parser->private_len ) ) + if ( FT_STREAM_SEEK( start_pos ) || + FT_QALLOC( parser->private_dict, parser->private_len ) ) goto Fail; parser->private_len = 0; @@ -450,7 +450,7 @@ if ( parser->in_memory ) { /* note that we allocate one more byte to put a terminating `0' */ - if ( FT_ALLOC( parser->private_dict, size + 1 ) ) + if ( FT_QALLOC( parser->private_dict, size + 1 ) ) goto Fail; parser->private_len = size; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 parser (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h 2022-07-14 08:05:38.000000000 +0000 @@ -4,7 +4,7 @@ * * Type 1 tokenizer (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2022 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/UPDATING.txt openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/UPDATING.txt --- openjdk-17-17.0.3+7/src/java.desktop/share/native/libfreetype/UPDATING.txt 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/libfreetype/UPDATING.txt 2022-07-14 08:05:38.000000000 +0000 @@ -30,6 +30,6 @@ When updating specify --with-freetype=bundled to test builds to expose build issues. -This is important because presently on Linux and Solaris the build +This is important because presently on Linux the build defaults to linking against the system library and does not attempt to compile the sources. diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsalpha.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsalpha.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsalpha.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsalpha.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,675 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Alpha copy ------------------------------------------------------------------------------------------------------------------ + +// This macro return words stored as big endian +#define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8)) + + +// Floor to byte, taking care of saturation +cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d) +{ + d += 0.5; + if (d <= 0) return 0; + if (d >= 255.0) return 255; + + return (cmsUInt8Number) _cmsQuickFloorWord(d); +} + + +// Return the size in bytes of a given formatter +static +cmsUInt32Number trueBytesSize(cmsUInt32Number Format) +{ + cmsUInt32Number fmt_bytes = T_BYTES(Format); + + // For double, the T_BYTES field returns zero + if (fmt_bytes == 0) + return sizeof(double); + + // Otherwise, it is already correct for all formats + return fmt_bytes; +} + + +// Several format converters + +typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src); + + +// From 8 + +static +void copy8(void* dst, const void* src) +{ + memmove(dst, src, 1); +} + +static +void from8to16(void* dst, const void* src) +{ + cmsUInt8Number n = *(cmsUInt8Number*)src; + *(cmsUInt16Number*) dst = (cmsUInt16Number) FROM_8_TO_16(n); +} + +static +void from8to16SE(void* dst, const void* src) +{ + cmsUInt8Number n = *(cmsUInt8Number*)src; + *(cmsUInt16Number*)dst = CHANGE_ENDIAN(FROM_8_TO_16(n)); +} + +static +void from8toFLT(void* dst, const void* src) +{ + *(cmsFloat32Number*)dst = (cmsFloat32Number) (*(cmsUInt8Number*)src) / 255.0f; +} + +static +void from8toDBL(void* dst, const void* src) +{ + *(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt8Number*)src) / 255.0; +} + +static +void from8toHLF(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} + +// From 16 + +static +void from16to8(void* dst, const void* src) +{ + cmsUInt16Number n = *(cmsUInt16Number*)src; + *(cmsUInt8Number*) dst = FROM_16_TO_8(n); +} + +static +void from16SEto8(void* dst, const void* src) +{ + cmsUInt16Number n = *(cmsUInt16Number*)src; + *(cmsUInt8Number*)dst = FROM_16_TO_8(CHANGE_ENDIAN(n)); +} + +static +void copy16(void* dst, const void* src) +{ + memmove(dst, src, 2); +} + +static +void from16to16(void* dst, const void* src) +{ + cmsUInt16Number n = *(cmsUInt16Number*)src; + *(cmsUInt16Number*)dst = CHANGE_ENDIAN(n); +} + +static +void from16toFLT(void* dst, const void* src) +{ + *(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f; +} + +static +void from16SEtoFLT(void* dst, const void* src) +{ + *(cmsFloat32Number*)dst = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f; +} + +static +void from16toDBL(void* dst, const void* src) +{ + *(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt16Number*)src) / 65535.0; +} + +static +void from16SEtoDBL(void* dst, const void* src) +{ + *(cmsFloat64Number*)dst = (cmsFloat64Number) (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0; +} + +static +void from16toHLF(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} + +static +void from16SEtoHLF(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + cmsFloat32Number n = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} +// From Float + +static +void fromFLTto8(void* dst, const void* src) +{ + cmsFloat32Number n = *(cmsFloat32Number*)src; + *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); +} + +static +void fromFLTto16(void* dst, const void* src) +{ + cmsFloat32Number n = *(cmsFloat32Number*)src; + *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); +} + +static +void fromFLTto16SE(void* dst, const void* src) +{ + cmsFloat32Number n = *(cmsFloat32Number*)src; + cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); + + *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); +} + +static +void copy32(void* dst, const void* src) +{ + memmove(dst, src, sizeof(cmsFloat32Number)); +} + +static +void fromFLTtoDBL(void* dst, const void* src) +{ + cmsFloat32Number n = *(cmsFloat32Number*)src; + *(cmsFloat64Number*)dst = (cmsFloat64Number)n; +} + +static +void fromFLTtoHLF(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + cmsFloat32Number n = *(cmsFloat32Number*)src; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} + + +// From HALF + +static +void fromHLFto8(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); + *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif + +} + +static +void fromHLFto16(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); + *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} + +static +void fromHLFto16SE(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); + cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); + *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} + +static +void fromHLFtoFLT(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + *(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} + +static +void fromHLFtoDBL(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + *(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} + +// From double +static +void fromDBLto8(void* dst, const void* src) +{ + cmsFloat64Number n = *(cmsFloat64Number*)src; + *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0); +} + +static +void fromDBLto16(void* dst, const void* src) +{ + cmsFloat64Number n = *(cmsFloat64Number*)src; + *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); +} + +static +void fromDBLto16SE(void* dst, const void* src) +{ + cmsFloat64Number n = *(cmsFloat64Number*)src; + cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); + *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); +} + +static +void fromDBLtoFLT(void* dst, const void* src) +{ + cmsFloat64Number n = *(cmsFloat64Number*)src; + *(cmsFloat32Number*)dst = (cmsFloat32Number) n; +} + +static +void fromDBLtoHLF(void* dst, const void* src) +{ +#ifndef CMS_NO_HALF_SUPPORT + cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +#else + cmsUNUSED_PARAMETER(dst); + cmsUNUSED_PARAMETER(src); +#endif +} + +static +void copy64(void* dst, const void* src) +{ + memmove(dst, src, sizeof(cmsFloat64Number)); +} + + +// Returns the position (x or y) of the formatter in the table of functions +static +int FormatterPos(cmsUInt32Number frm) +{ + cmsUInt32Number b = T_BYTES(frm); + + if (b == 0 && T_FLOAT(frm)) + return 5; // DBL +#ifndef CMS_NO_HALF_SUPPORT + if (b == 2 && T_FLOAT(frm)) + return 3; // HLF +#endif + if (b == 4 && T_FLOAT(frm)) + return 4; // FLT + if (b == 2 && !T_FLOAT(frm)) + { + if (T_ENDIAN16(frm)) + return 2; // 16SE + else + return 1; // 16 + } + if (b == 1 && !T_FLOAT(frm)) + return 0; // 8 + return -1; // not recognized +} + +// Obtains an alpha-to-alpha function formatter +static +cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out) +{ +static cmsFormatterAlphaFn FormattersAlpha[6][6] = { + + /* from 8 */ { copy8, from8to16, from8to16SE, from8toHLF, from8toFLT, from8toDBL }, + /* from 16*/ { from16to8, copy16, from16to16, from16toHLF, from16toFLT, from16toDBL }, + /* from 16SE*/{ from16SEto8, from16to16, copy16, from16SEtoHLF,from16SEtoFLT, from16SEtoDBL }, + /* from HLF*/ { fromHLFto8, fromHLFto16, fromHLFto16SE, copy16, fromHLFtoFLT, fromHLFtoDBL }, + /* from FLT*/ { fromFLTto8, fromFLTto16, fromFLTto16SE, fromFLTtoHLF, copy32, fromFLTtoDBL }, + /* from DBL*/ { fromDBLto8, fromDBLto16, fromDBLto16SE, fromDBLtoHLF, fromDBLtoFLT, copy64 }}; + + int in_n = FormatterPos(in); + int out_n = FormatterPos(out); + + if (in_n < 0 || out_n < 0 || in_n > 5 || out_n > 5) { + + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width"); + return NULL; + } + + return FormattersAlpha[in_n][out_n]; +} + + + +// This function computes the distance from each component to the next one in bytes. +static +void ComputeIncrementsForChunky(cmsUInt32Number Format, + cmsUInt32Number ComponentStartingOrder[], + cmsUInt32Number ComponentPointerIncrements[]) +{ + cmsUInt32Number channels[cmsMAXCHANNELS]; + cmsUInt32Number extra = T_EXTRA(Format); + cmsUInt32Number nchannels = T_CHANNELS(Format); + cmsUInt32Number total_chans = nchannels + extra; + cmsUInt32Number i; + cmsUInt32Number channelSize = trueBytesSize(Format); + cmsUInt32Number pixelSize = channelSize * total_chans; + + // Sanity check + if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) + return; + + memset(channels, 0, sizeof(channels)); + + // Separation is independent of starting point and only depends on channel size + for (i = 0; i < extra; i++) + ComponentPointerIncrements[i] = pixelSize; + + // Handle do swap + for (i = 0; i < total_chans; i++) + { + if (T_DOSWAP(Format)) { + channels[i] = total_chans - i - 1; + } + else { + channels[i] = i; + } + } + + // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012 + if (T_SWAPFIRST(Format) && total_chans > 1) { + + cmsUInt32Number tmp = channels[0]; + for (i = 0; i < total_chans-1; i++) + channels[i] = channels[i + 1]; + + channels[total_chans - 1] = tmp; + } + + // Handle size + if (channelSize > 1) + for (i = 0; i < total_chans; i++) { + channels[i] *= channelSize; + } + + for (i = 0; i < extra; i++) + ComponentStartingOrder[i] = channels[i + nchannels]; +} + + + +// On planar configurations, the distance is the stride added to any non-negative +static +void ComputeIncrementsForPlanar(cmsUInt32Number Format, + cmsUInt32Number BytesPerPlane, + cmsUInt32Number ComponentStartingOrder[], + cmsUInt32Number ComponentPointerIncrements[]) +{ + cmsUInt32Number channels[cmsMAXCHANNELS]; + cmsUInt32Number extra = T_EXTRA(Format); + cmsUInt32Number nchannels = T_CHANNELS(Format); + cmsUInt32Number total_chans = nchannels + extra; + cmsUInt32Number i; + cmsUInt32Number channelSize = trueBytesSize(Format); + + // Sanity check + if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) + return; + + memset(channels, 0, sizeof(channels)); + + // Separation is independent of starting point and only depends on channel size + for (i = 0; i < extra; i++) + ComponentPointerIncrements[i] = channelSize; + + // Handle do swap + for (i = 0; i < total_chans; i++) + { + if (T_DOSWAP(Format)) { + channels[i] = total_chans - i - 1; + } + else { + channels[i] = i; + } + } + + // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012 + if (T_SWAPFIRST(Format) && total_chans > 0) { + + cmsUInt32Number tmp = channels[0]; + for (i = 0; i < total_chans - 1; i++) + channels[i] = channels[i + 1]; + + channels[total_chans - 1] = tmp; + } + + // Handle size + for (i = 0; i < total_chans; i++) { + channels[i] *= BytesPerPlane; + } + + for (i = 0; i < extra; i++) + ComponentStartingOrder[i] = channels[i + nchannels]; +} + + + +// Dispatcher por chunky and planar RGB +static +void ComputeComponentIncrements(cmsUInt32Number Format, + cmsUInt32Number BytesPerPlane, + cmsUInt32Number ComponentStartingOrder[], + cmsUInt32Number ComponentPointerIncrements[]) +{ + if (T_PLANAR(Format)) { + + ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements); + } + else { + ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements); + } + +} + + + +// Handles extra channels copying alpha if requested by the flags +void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + cmsUInt32Number i, j, k; + cmsUInt32Number nExtra; + cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS]; + cmsUInt32Number SourceIncrements[cmsMAXCHANNELS]; + cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS]; + cmsUInt32Number DestIncrements[cmsMAXCHANNELS]; + + cmsFormatterAlphaFn copyValueFn; + + // Make sure we need some copy + if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA)) + return; + + // Exit early if in-place color-management is occurring - no need to copy extra channels to themselves. + if (p->InputFormat == p->OutputFormat && in == out) + return; + + // Make sure we have same number of alpha channels. If not, just return as this should be checked at transform creation time. + nExtra = T_EXTRA(p->InputFormat); + if (nExtra != T_EXTRA(p->OutputFormat)) + return; + + // Anything to do? + if (nExtra == 0) + return; + + // Compute the increments + ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements); + ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements); + + // Check for conversions 8, 16, half, float, dbl + copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat); + if (copyValueFn == NULL) + return; + + if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly + + cmsUInt8Number* SourcePtr; + cmsUInt8Number* DestPtr; + + cmsUInt32Number SourceStrideIncrement = 0; + cmsUInt32Number DestStrideIncrement = 0; + + // The loop itself + for (i = 0; i < LineCount; i++) { + + // Prepare pointers for the loop + SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement; + DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement; + + for (j = 0; j < PixelsPerLine; j++) { + + copyValueFn(DestPtr, SourcePtr); + + SourcePtr += SourceIncrements[0]; + DestPtr += DestIncrements[0]; + } + + SourceStrideIncrement += Stride->BytesPerLineIn; + DestStrideIncrement += Stride->BytesPerLineOut; + } + + } + else { // General case with more than one extra channel + + cmsUInt8Number* SourcePtr[cmsMAXCHANNELS]; + cmsUInt8Number* DestPtr[cmsMAXCHANNELS]; + + cmsUInt32Number SourceStrideIncrements[cmsMAXCHANNELS]; + cmsUInt32Number DestStrideIncrements[cmsMAXCHANNELS]; + + memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements)); + memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements)); + + // The loop itself + for (i = 0; i < LineCount; i++) { + + // Prepare pointers for the loop + for (j = 0; j < nExtra; j++) { + + SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j]; + DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j]; + } + + for (j = 0; j < PixelsPerLine; j++) { + + for (k = 0; k < nExtra; k++) { + + copyValueFn(DestPtr[k], SourcePtr[k]); + + SourcePtr[k] += SourceIncrements[k]; + DestPtr[k] += DestIncrements[k]; + } + } + + for (j = 0; j < nExtra; j++) { + + SourceStrideIncrements[j] += Stride->BytesPerLineIn; + DestStrideIncrements[j] += Stride->BytesPerLineOut; + } + } + } +} + + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmscam02.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmscam02.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmscam02.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmscam02.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,515 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging. + +// ---------- Implementation -------------------------------------------- + +typedef struct { + + cmsFloat64Number XYZ[3]; + cmsFloat64Number RGB[3]; + cmsFloat64Number RGBc[3]; + cmsFloat64Number RGBp[3]; + cmsFloat64Number RGBpa[3]; + cmsFloat64Number a, b, h, e, H, A, J, Q, s, t, C, M; + cmsFloat64Number abC[2]; + cmsFloat64Number abs[2]; + cmsFloat64Number abM[2]; + +} CAM02COLOR; + +typedef struct { + + CAM02COLOR adoptedWhite; + cmsFloat64Number LA, Yb; + cmsFloat64Number F, c, Nc; + cmsUInt32Number surround; + cmsFloat64Number n, Nbb, Ncb, z, FL, D; + + cmsContext ContextID; + +} cmsCIECAM02; + + +static +cmsFloat64Number compute_n(cmsCIECAM02* pMod) +{ + return (pMod -> Yb / pMod -> adoptedWhite.XYZ[1]); +} + +static +cmsFloat64Number compute_z(cmsCIECAM02* pMod) +{ + return (1.48 + pow(pMod -> n, 0.5)); +} + +static +cmsFloat64Number computeNbb(cmsCIECAM02* pMod) +{ + return (0.725 * pow((1.0 / pMod -> n), 0.2)); +} + +static +cmsFloat64Number computeFL(cmsCIECAM02* pMod) +{ + cmsFloat64Number k, FL; + + k = 1.0 / ((5.0 * pMod->LA) + 1.0); + FL = 0.2 * pow(k, 4.0) * (5.0 * pMod->LA) + 0.1 * + (pow((1.0 - pow(k, 4.0)), 2.0)) * + (pow((5.0 * pMod->LA), (1.0 / 3.0))); + + return FL; +} + +static +cmsFloat64Number computeD(cmsCIECAM02* pMod) +{ + cmsFloat64Number D; + + D = pMod->F - (1.0/3.6)*(exp(((-pMod ->LA-42) / 92.0))); + + return D; +} + + +static +CAM02COLOR XYZtoCAT02(CAM02COLOR clr) +{ + clr.RGB[0] = (clr.XYZ[0] * 0.7328) + (clr.XYZ[1] * 0.4296) + (clr.XYZ[2] * -0.1624); + clr.RGB[1] = (clr.XYZ[0] * -0.7036) + (clr.XYZ[1] * 1.6975) + (clr.XYZ[2] * 0.0061); + clr.RGB[2] = (clr.XYZ[0] * 0.0030) + (clr.XYZ[1] * 0.0136) + (clr.XYZ[2] * 0.9834); + + return clr; +} + +static +CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsUInt32Number i; + + for (i = 0; i < 3; i++) { + clr.RGBc[i] = ((pMod -> adoptedWhite.XYZ[1] * + (pMod->D / pMod -> adoptedWhite.RGB[i])) + + (1.0 - pMod->D)) * clr.RGB[i]; + } + + return clr; +} + + +static +CAM02COLOR CAT02toHPE(CAM02COLOR clr) +{ + cmsFloat64Number M[9]; + + M[0] =(( 0.38971 * 1.096124) + (0.68898 * 0.454369) + (-0.07868 * -0.009628)); + M[1] =(( 0.38971 * -0.278869) + (0.68898 * 0.473533) + (-0.07868 * -0.005698)); + M[2] =(( 0.38971 * 0.182745) + (0.68898 * 0.072098) + (-0.07868 * 1.015326)); + M[3] =((-0.22981 * 1.096124) + (1.18340 * 0.454369) + ( 0.04641 * -0.009628)); + M[4] =((-0.22981 * -0.278869) + (1.18340 * 0.473533) + ( 0.04641 * -0.005698)); + M[5] =((-0.22981 * 0.182745) + (1.18340 * 0.072098) + ( 0.04641 * 1.015326)); + M[6] =(-0.009628); + M[7] =(-0.005698); + M[8] =( 1.015326); + + clr.RGBp[0] = (clr.RGBc[0] * M[0]) + (clr.RGBc[1] * M[1]) + (clr.RGBc[2] * M[2]); + clr.RGBp[1] = (clr.RGBc[0] * M[3]) + (clr.RGBc[1] * M[4]) + (clr.RGBc[2] * M[5]); + clr.RGBp[2] = (clr.RGBc[0] * M[6]) + (clr.RGBc[1] * M[7]) + (clr.RGBc[2] * M[8]); + + return clr; +} + +static +CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsUInt32Number i; + cmsFloat64Number temp; + + for (i = 0; i < 3; i++) { + if (clr.RGBp[i] < 0) { + + temp = pow((-1.0 * pMod->FL * clr.RGBp[i] / 100.0), 0.42); + clr.RGBpa[i] = (-1.0 * 400.0 * temp) / (temp + 27.13) + 0.1; + } + else { + temp = pow((pMod->FL * clr.RGBp[i] / 100.0), 0.42); + clr.RGBpa[i] = (400.0 * temp) / (temp + 27.13) + 0.1; + } + } + + clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] + + (clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb; + + return clr; +} + +static +CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsFloat64Number a, b, temp, e, t, r2d, d2r; + + a = clr.RGBpa[0] - (12.0 * clr.RGBpa[1] / 11.0) + (clr.RGBpa[2] / 11.0); + b = (clr.RGBpa[0] + clr.RGBpa[1] - (2.0 * clr.RGBpa[2])) / 9.0; + + r2d = (180.0 / 3.141592654); + if (a == 0) { + if (b == 0) clr.h = 0; + else if (b > 0) clr.h = 90; + else clr.h = 270; + } + else if (a > 0) { + temp = b / a; + if (b > 0) clr.h = (r2d * atan(temp)); + else if (b == 0) clr.h = 0; + else clr.h = (r2d * atan(temp)) + 360; + } + else { + temp = b / a; + clr.h = (r2d * atan(temp)) + 180; + } + + d2r = (3.141592654 / 180.0); + e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * + (cos((clr.h * d2r + 2.0)) + 3.8); + + if (clr.h < 20.14) { + temp = ((clr.h + 122.47)/1.2) + ((20.14 - clr.h)/0.8); + clr.H = 300 + (100*((clr.h + 122.47)/1.2)) / temp; + } + else if (clr.h < 90.0) { + temp = ((clr.h - 20.14)/0.8) + ((90.00 - clr.h)/0.7); + clr.H = (100*((clr.h - 20.14)/0.8)) / temp; + } + else if (clr.h < 164.25) { + temp = ((clr.h - 90.00)/0.7) + ((164.25 - clr.h)/1.0); + clr.H = 100 + ((100*((clr.h - 90.00)/0.7)) / temp); + } + else if (clr.h < 237.53) { + temp = ((clr.h - 164.25)/1.0) + ((237.53 - clr.h)/1.2); + clr.H = 200 + ((100*((clr.h - 164.25)/1.0)) / temp); + } + else { + temp = ((clr.h - 237.53)/1.2) + ((360 - clr.h + 20.14)/0.8); + clr.H = 300 + ((100*((clr.h - 237.53)/1.2)) / temp); + } + + clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A), + (pMod->c * pMod->z)); + + clr.Q = (4.0 / pMod->c) * pow((clr.J / 100.0), 0.5) * + (pMod->adoptedWhite.A + 4.0) * pow(pMod->FL, 0.25); + + t = (e * pow(((a * a) + (b * b)), 0.5)) / + (clr.RGBpa[0] + clr.RGBpa[1] + + ((21.0 / 20.0) * clr.RGBpa[2])); + + clr.C = pow(t, 0.9) * pow((clr.J / 100.0), 0.5) * + pow((1.64 - pow(0.29, pMod->n)), 0.73); + + clr.M = clr.C * pow(pMod->FL, 0.25); + clr.s = 100.0 * pow((clr.M / clr.Q), 0.5); + + return clr; +} + + +static +CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + + cmsFloat64Number t, e, p1, p2, p3, p4, p5, hr, d2r; + d2r = 3.141592654 / 180.0; + + t = pow( (clr.C / (pow((clr.J / 100.0), 0.5) * + (pow((1.64 - pow(0.29, pMod->n)), 0.73)))), + (1.0 / 0.9) ); + e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) * + (cos((clr.h * d2r + 2.0)) + 3.8); + + clr.A = pMod->adoptedWhite.A * pow( + (clr.J / 100.0), + (1.0 / (pMod->c * pMod->z))); + + p1 = e / t; + p2 = (clr.A / pMod->Nbb) + 0.305; + p3 = 21.0 / 20.0; + + hr = clr.h * d2r; + + if (fabs(sin(hr)) >= fabs(cos(hr))) { + p4 = p1 / sin(hr); + clr.b = (p2 * (2.0 + p3) * (460.0 / 1403.0)) / + (p4 + (2.0 + p3) * (220.0 / 1403.0) * + (cos(hr) / sin(hr)) - (27.0 / 1403.0) + + p3 * (6300.0 / 1403.0)); + clr.a = clr.b * (cos(hr) / sin(hr)); + } + else { + p5 = p1 / cos(hr); + clr.a = (p2 * (2.0 + p3) * (460.0 / 1403.0)) / + (p5 + (2.0 + p3) * (220.0 / 1403.0) - + ((27.0 / 1403.0) - p3 * (6300.0 / 1403.0)) * + (sin(hr) / cos(hr))); + clr.b = clr.a * (sin(hr) / cos(hr)); + } + + clr.RGBpa[0] = ((460.0 / 1403.0) * p2) + + ((451.0 / 1403.0) * clr.a) + + ((288.0 / 1403.0) * clr.b); + clr.RGBpa[1] = ((460.0 / 1403.0) * p2) - + ((891.0 / 1403.0) * clr.a) - + ((261.0 / 1403.0) * clr.b); + clr.RGBpa[2] = ((460.0 / 1403.0) * p2) - + ((220.0 / 1403.0) * clr.a) - + ((6300.0 / 1403.0) * clr.b); + + return clr; +} + +static +CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsUInt32Number i; + cmsFloat64Number c1; + + for (i = 0; i < 3; i++) { + if ((clr.RGBpa[i] - 0.1) < 0) c1 = -1; + else c1 = 1; + clr.RGBp[i] = c1 * (100.0 / pMod->FL) * + pow(((27.13 * fabs(clr.RGBpa[i] - 0.1)) / + (400.0 - fabs(clr.RGBpa[i] - 0.1))), + (1.0 / 0.42)); + } + + return clr; +} + +static +CAM02COLOR HPEtoCAT02(CAM02COLOR clr) +{ + cmsFloat64Number M[9]; + + M[0] = (( 0.7328 * 1.910197) + (0.4296 * 0.370950)); + M[1] = (( 0.7328 * -1.112124) + (0.4296 * 0.629054)); + M[2] = (( 0.7328 * 0.201908) + (0.4296 * 0.000008) - 0.1624); + M[3] = ((-0.7036 * 1.910197) + (1.6975 * 0.370950)); + M[4] = ((-0.7036 * -1.112124) + (1.6975 * 0.629054)); + M[5] = ((-0.7036 * 0.201908) + (1.6975 * 0.000008) + 0.0061); + M[6] = (( 0.0030 * 1.910197) + (0.0136 * 0.370950)); + M[7] = (( 0.0030 * -1.112124) + (0.0136 * 0.629054)); + M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834);; + + clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]); + clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]); + clr.RGBc[2] = (clr.RGBp[0] * M[6]) + (clr.RGBp[1] * M[7]) + (clr.RGBp[2] * M[8]); + return clr; +} + + +static +CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod) +{ + cmsUInt32Number i; + for (i = 0; i < 3; i++) { + clr.RGB[i] = clr.RGBc[i] / + ((pMod->adoptedWhite.XYZ[1] * pMod->D / pMod->adoptedWhite.RGB[i]) + 1.0 - pMod->D); + } + return clr; +} + + +static +CAM02COLOR CAT02toXYZ(CAM02COLOR clr) +{ + clr.XYZ[0] = (clr.RGB[0] * 1.096124) + (clr.RGB[1] * -0.278869) + (clr.RGB[2] * 0.182745); + clr.XYZ[1] = (clr.RGB[0] * 0.454369) + (clr.RGB[1] * 0.473533) + (clr.RGB[2] * 0.072098); + clr.XYZ[2] = (clr.RGB[0] * -0.009628) + (clr.RGB[1] * -0.005698) + (clr.RGB[2] * 1.015326); + + return clr; +} + + +cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC) +{ + cmsCIECAM02* lpMod; + + _cmsAssert(pVC != NULL); + + if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) { + return NULL; + } + + lpMod ->ContextID = ContextID; + + lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X; + lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y; + lpMod ->adoptedWhite.XYZ[2] = pVC ->whitePoint.Z; + + lpMod -> LA = pVC ->La; + lpMod -> Yb = pVC ->Yb; + lpMod -> D = pVC ->D_value; + lpMod -> surround = pVC ->surround; + + switch (lpMod -> surround) { + + + case CUTSHEET_SURROUND: + lpMod->F = 0.8; + lpMod->c = 0.41; + lpMod->Nc = 0.8; + break; + + case DARK_SURROUND: + lpMod -> F = 0.8; + lpMod -> c = 0.525; + lpMod -> Nc = 0.8; + break; + + case DIM_SURROUND: + lpMod -> F = 0.9; + lpMod -> c = 0.59; + lpMod -> Nc = 0.95; + break; + + default: + // Average surround + lpMod -> F = 1.0; + lpMod -> c = 0.69; + lpMod -> Nc = 1.0; + } + + lpMod -> n = compute_n(lpMod); + lpMod -> z = compute_z(lpMod); + lpMod -> Nbb = computeNbb(lpMod); + lpMod -> FL = computeFL(lpMod); + + if (lpMod -> D == D_CALCULATE) { + lpMod -> D = computeD(lpMod); + } + + lpMod -> Ncb = lpMod -> Nbb; + + lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite); + lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod); + lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite); + lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod); + + return (cmsHANDLE) lpMod; + +} + +void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel) +{ + cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; + + if (lpMod) _cmsFree(lpMod ->ContextID, lpMod); +} + + +void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut) +{ + CAM02COLOR clr; + cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; + + _cmsAssert(lpMod != NULL); + _cmsAssert(pIn != NULL); + _cmsAssert(pOut != NULL); + + memset(&clr, 0, sizeof(clr)); + + clr.XYZ[0] = pIn ->X; + clr.XYZ[1] = pIn ->Y; + clr.XYZ[2] = pIn ->Z; + + clr = XYZtoCAT02(clr); + clr = ChromaticAdaptation(clr, lpMod); + clr = CAT02toHPE(clr); + clr = NonlinearCompression(clr, lpMod); + clr = ComputeCorrelates(clr, lpMod); + + pOut ->J = clr.J; + pOut ->C = clr.C; + pOut ->h = clr.h; +} + +void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut) +{ + CAM02COLOR clr; + cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; + + _cmsAssert(lpMod != NULL); + _cmsAssert(pIn != NULL); + _cmsAssert(pOut != NULL); + + memset(&clr, 0, sizeof(clr)); + + clr.J = pIn -> J; + clr.C = pIn -> C; + clr.h = pIn -> h; + + clr = InverseCorrelates(clr, lpMod); + clr = InverseNonlinearity(clr, lpMod); + clr = HPEtoCAT02(clr); + clr = InverseChromaticAdaptation(clr, lpMod); + clr = CAT02toXYZ(clr); + + pOut ->X = clr.XYZ[0]; + pOut ->Y = clr.XYZ[1]; + pOut ->Z = clr.XYZ[2]; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmscgats.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmscgats.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmscgats.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmscgats.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,2815 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- + + +#define MAXID 128 // Max length of identifier +#define MAXSTR 1024 // Max length of string +#define MAXTABLES 255 // Max Number of tables in a single stream +#define MAXINCLUDE 20 // Max number of nested includes + +#define DEFAULT_DBL_FORMAT "%.10g" // Double formatting + +#ifdef CMS_IS_WINDOWS_ +# include +# define DIR_CHAR '\\' +#else +# define DIR_CHAR '/' +#endif + + +// Symbols +typedef enum { + + SUNDEFINED, + SINUM, // Integer + SDNUM, // Real + SIDENT, // Identifier + SSTRING, // string + SCOMMENT, // comment + SEOLN, // End of line + SEOF, // End of stream + SSYNERROR, // Syntax error found on stream + + // Keywords + + SBEGIN_DATA, + SBEGIN_DATA_FORMAT, + SEND_DATA, + SEND_DATA_FORMAT, + SKEYWORD, + SDATA_FORMAT_ID, + SINCLUDE + + } SYMBOL; + + +// How to write the value +typedef enum { + + WRITE_UNCOOKED, + WRITE_STRINGIFY, + WRITE_HEXADECIMAL, + WRITE_BINARY, + WRITE_PAIR + + } WRITEMODE; + +// Linked list of variable names +typedef struct _KeyVal { + + struct _KeyVal* Next; + char* Keyword; // Name of variable + struct _KeyVal* NextSubkey; // If key is a dictionary, points to the next item + char* Subkey; // If key is a dictionary, points to the subkey name + char* Value; // Points to value + WRITEMODE WriteAs; // How to write the value + + } KEYVALUE; + + +// Linked list of memory chunks (Memory sink) +typedef struct _OwnedMem { + + struct _OwnedMem* Next; + void * Ptr; // Point to value + + } OWNEDMEM; + +// Suballocator +typedef struct _SubAllocator { + + cmsUInt8Number* Block; + cmsUInt32Number BlockSize; + cmsUInt32Number Used; + + } SUBALLOCATOR; + +// Table. Each individual table can hold properties and rows & cols +typedef struct _Table { + + char SheetType[MAXSTR]; // The first row of the IT8 (the type) + + int nSamples, nPatches; // Cols, Rows + int SampleID; // Pos of ID + + KEYVALUE* HeaderList; // The properties + + char** DataFormat; // The binary stream descriptor + char** Data; // The binary stream + + } TABLE; + +// File stream being parsed +typedef struct _FileContext { + char FileName[cmsMAX_PATH]; // File name if being read from file + FILE* Stream; // File stream or NULL if holded in memory + } FILECTX; + +// This struct hold all information about an open IT8 handler. +typedef struct { + + + cmsUInt32Number TablesCount; // How many tables in this stream + cmsUInt32Number nTable; // The actual table + + TABLE Tab[MAXTABLES]; + + // Memory management + OWNEDMEM* MemorySink; // The storage backend + SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast + + // Parser state machine + SYMBOL sy; // Current symbol + int ch; // Current character + + cmsInt32Number inum; // integer value + cmsFloat64Number dnum; // real value + + char id[MAXID]; // identifier + char str[MAXSTR]; // string + + // Allowed keywords & datasets. They have visibility on whole stream + KEYVALUE* ValidKeywords; + KEYVALUE* ValidSampleID; + + char* Source; // Points to loc. being parsed + cmsInt32Number lineno; // line counter for error reporting + + FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed + cmsInt32Number IncludeSP; // Include Stack Pointer + + char* MemoryBlock; // The stream if holded in memory + + char DoubleFormatter[MAXID];// Printf-like 'cmsFloat64Number' formatter + + cmsContext ContextID; // The threading context + + } cmsIT8; + + +// The stream for save operations +typedef struct { + + FILE* stream; // For save-to-file behaviour + + cmsUInt8Number* Base; + cmsUInt8Number* Ptr; // For save-to-mem behaviour + cmsUInt32Number Used; + cmsUInt32Number Max; + + } SAVESTREAM; + + +// ------------------------------------------------------ cmsIT8 parsing routines + + +// A keyword +typedef struct { + + const char *id; + SYMBOL sy; + + } KEYWORD; + +// The keyword->symbol translation table. Sorting is required. +static const KEYWORD TabKeys[] = { + + {"$INCLUDE", SINCLUDE}, // This is an extension! + {".INCLUDE", SINCLUDE}, // This is an extension! + + {"BEGIN_DATA", SBEGIN_DATA }, + {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT }, + {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID}, + {"END_DATA", SEND_DATA}, + {"END_DATA_FORMAT", SEND_DATA_FORMAT}, + {"KEYWORD", SKEYWORD} + }; + +#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD)) + +// Predefined properties + +// A property +typedef struct { + const char *id; // The identifier + WRITEMODE as; // How is supposed to be written + } PROPERTY; + +static PROPERTY PredefinedProperties[] = { + + {"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS + {"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS + {"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file. + {"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. + {"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file. + {"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. + {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal". + {"MANUFACTURER", WRITE_STRINGIFY}, + {"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value + {"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm. + {"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target. + + {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code + // uniquely identifying th e material. This is intend ed to be used for IT8.7 + // physical targets only (i.e . IT8.7/1 a nd IT8.7/2). + + {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and + // model number) to generate the data reported. This data will often + // provide more information about the particular data collected than an + // extensive list of specific details. This is particularly important for + // spectral data or data derived from spectrophotometry. + + {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide + // a guide to the potential for issues of paper fluorescence, etc. + + {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported. + // Where standard conditions have been defined (e.g., SWOP at nominal) + // named conditions may suffice. Otherwise, detailed information is + // needed. + + {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during + // measurement. Allowed values are "black", "white", or {"na". + + {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic + // below properties are new in recent specs: + + {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated + // along with details of the geometry and the aperture size and shape. For example, + // for transmission measurements it is important to identify 0/diffuse, diffuse/0, + // opal or integrating sphere, etc. For reflection it is important to identify 0/45, + // 45/0, sphere (specular included or excluded), etc. + + {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to + // denote the use of filters such as none, D65, Red, Green or Blue. + + {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed + // values are {"yes", "white", "none" or "na". + + {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the + // calculation of various data parameters (2 degree and 10 degree), CIE standard + // illuminant functions used in the calculation of various data parameters (e.g., D50, + // D65, etc.), density status response, etc. If used there shall be at least one + // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute + // in the set shall be {"name" and shall identify the particular parameter used. + // The second shall be {"value" and shall provide the value associated with that name. + // For ASCII data, a string containing the Name and Value attribute pairs shall follow + // the weighting function keyword. A semi-colon separates attribute pairs from each + // other and within the attribute the name and value are separated by a comma. + + {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name + // of the calculation, parameter is the name of the parameter used in the calculation + // and value is the value of the parameter. + + {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc. + + {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target. + + {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table. + + {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table. +}; + +#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY)) + + +// Predefined sample types on dataset +static const char* PredefinedSampleID[] = { + "SAMPLE_ID", // Identifies sample that data represents + "STRING", // Identifies label, or other non-machine readable value. + // Value must begin and end with a " symbol + + "CMYK_C", // Cyan component of CMYK data expressed as a percentage + "CMYK_M", // Magenta component of CMYK data expressed as a percentage + "CMYK_Y", // Yellow component of CMYK data expressed as a percentage + "CMYK_K", // Black component of CMYK data expressed as a percentage + "D_RED", // Red filter density + "D_GREEN", // Green filter density + "D_BLUE", // Blue filter density + "D_VIS", // Visual filter density + "D_MAJOR_FILTER", // Major filter d ensity + "RGB_R", // Red component of RGB data + "RGB_G", // Green component of RGB data + "RGB_B", // Blue com ponent of RGB data + "SPECTRAL_NM", // Wavelength of measurement expressed in nanometers + "SPECTRAL_PCT", // Percentage reflectance/transmittance + "SPECTRAL_DEC", // Reflectance/transmittance + "XYZ_X", // X component of tristimulus data + "XYZ_Y", // Y component of tristimulus data + "XYZ_Z", // Z component of tristimulus data + "XYY_X", // x component of chromaticity data + "XYY_Y", // y component of chromaticity data + "XYY_CAPY", // Y component of tristimulus data + "LAB_L", // L* component of Lab data + "LAB_A", // a* component of Lab data + "LAB_B", // b* component of Lab data + "LAB_C", // C*ab component of Lab data + "LAB_H", // hab component of Lab data + "LAB_DE", // CIE dE + "LAB_DE_94", // CIE dE using CIE 94 + "LAB_DE_CMC", // dE using CMC + "LAB_DE_2000", // CIE dE using CIE DE 2000 + "MEAN_DE", // Mean Delta E (LAB_DE) of samples compared to batch average + // (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets) + "STDEV_X", // Standard deviation of X (tristimulus data) + "STDEV_Y", // Standard deviation of Y (tristimulus data) + "STDEV_Z", // Standard deviation of Z (tristimulus data) + "STDEV_L", // Standard deviation of L* + "STDEV_A", // Standard deviation of a* + "STDEV_B", // Standard deviation of b* + "STDEV_DE", // Standard deviation of CIE dE + "CHI_SQD_PAR"}; // The average of the standard deviations of L*, a* and b*. It is + // used to derive an estimate of the chi-squared parameter which is + // recommended as the predictor of the variability of dE + +#define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *)) + +//Forward declaration of some internal functions +static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size); + +// Checks whatever c is a separator +static +cmsBool isseparator(int c) +{ + return (c == ' ') || (c == '\t') ; +} + +// Checks whatever c is a valid identifier char +static +cmsBool ismiddle(int c) +{ + return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); +} + +// Checks whatsever c is a valid identifier middle char. +static +cmsBool isidchar(int c) +{ + return isalnum(c) || ismiddle(c); +} + +// Checks whatsever c is a valid identifier first char. +static +cmsBool isfirstidchar(int c) +{ + return !isdigit(c) && ismiddle(c); +} + +// Guess whether the supplied path looks like an absolute path +static +cmsBool isabsolutepath(const char *path) +{ + char ThreeChars[4]; + + if(path == NULL) + return FALSE; + if (path[0] == 0) + return FALSE; + + strncpy(ThreeChars, path, 3); + ThreeChars[3] = 0; + + if(ThreeChars[0] == DIR_CHAR) + return TRUE; + +#ifdef CMS_IS_WINDOWS_ + if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':') + return TRUE; +#endif + return FALSE; +} + + +// Makes a file path based on a given reference path +// NOTE: this function doesn't check if the path exists or even if it's legal +static +cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen) +{ + char *tail; + cmsUInt32Number len; + + // Already absolute? + if (isabsolutepath(relPath)) { + + strncpy(buffer, relPath, MaxLen); + buffer[MaxLen-1] = 0; + return TRUE; + } + + // No, search for last + strncpy(buffer, basePath, MaxLen); + buffer[MaxLen-1] = 0; + + tail = strrchr(buffer, DIR_CHAR); + if (tail == NULL) return FALSE; // Is not absolute and has no separators?? + + len = (cmsUInt32Number) (tail - buffer); + if (len >= MaxLen) return FALSE; + + // No need to assure zero terminator over here + strncpy(tail + 1, relPath, MaxLen - len); + + return TRUE; +} + + +// Make sure no exploit is being even tried +static +const char* NoMeta(const char* str) +{ + if (strchr(str, '%') != NULL) + return "**** CORRUPTED FORMAT STRING ***"; + + return str; +} + +// Syntax error +static +cmsBool SynError(cmsIT8* it8, const char *Txt, ...) +{ + char Buffer[256], ErrMsg[1024]; + va_list args; + + va_start(args, Txt); + vsnprintf(Buffer, 255, Txt, args); + Buffer[255] = 0; + va_end(args); + + snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer); + ErrMsg[1023] = 0; + it8->sy = SSYNERROR; + cmsSignalError(it8 ->ContextID, cmsERROR_CORRUPTION_DETECTED, "%s", ErrMsg); + return FALSE; +} + +// Check if current symbol is same as specified. issue an error else. +static +cmsBool Check(cmsIT8* it8, SYMBOL sy, const char* Err) +{ + if (it8 -> sy != sy) + return SynError(it8, NoMeta(Err)); + return TRUE; +} + +// Read Next character from stream +static +void NextCh(cmsIT8* it8) +{ + if (it8 -> FileStack[it8 ->IncludeSP]->Stream) { + + it8 ->ch = fgetc(it8 ->FileStack[it8 ->IncludeSP]->Stream); + + if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream)) { + + if (it8 ->IncludeSP > 0) { + + fclose(it8 ->FileStack[it8->IncludeSP--]->Stream); + it8 -> ch = ' '; // Whitespace to be ignored + + } else + it8 ->ch = 0; // EOF + } + } + else { + it8->ch = *it8->Source; + if (it8->ch) it8->Source++; + } +} + + +// Try to see if current identifier is a keyword, if so return the referred symbol +static +SYMBOL BinSrchKey(const char *id) +{ + int l = 1; + int r = NUMKEYS; + int x, res; + + while (r >= l) + { + x = (l+r)/2; + res = cmsstrcasecmp(id, TabKeys[x-1].id); + if (res == 0) return TabKeys[x-1].sy; + if (res < 0) r = x - 1; + else l = x + 1; + } + + return SUNDEFINED; +} + + +// 10 ^n +static +cmsFloat64Number xpow10(int n) +{ + return pow(10, (cmsFloat64Number) n); +} + + +// Reads a Real number, tries to follow from integer number +static +void ReadReal(cmsIT8* it8, cmsInt32Number inum) +{ + it8->dnum = (cmsFloat64Number)inum; + + while (isdigit(it8->ch)) { + + it8->dnum = (cmsFloat64Number)it8->dnum * 10.0 + (cmsFloat64Number)(it8->ch - '0'); + NextCh(it8); + } + + if (it8->ch == '.') { // Decimal point + + cmsFloat64Number frac = 0.0; // fraction + int prec = 0; // precision + + NextCh(it8); // Eats dec. point + + while (isdigit(it8->ch)) { + + frac = frac * 10.0 + (cmsFloat64Number)(it8->ch - '0'); + prec++; + NextCh(it8); + } + + it8->dnum = it8->dnum + (frac / xpow10(prec)); + } + + // Exponent, example 34.00E+20 + if (toupper(it8->ch) == 'E') { + + cmsInt32Number e; + cmsInt32Number sgn; + + NextCh(it8); sgn = 1; + + if (it8->ch == '-') { + + sgn = -1; NextCh(it8); + } + else + if (it8->ch == '+') { + + sgn = +1; + NextCh(it8); + } + + e = 0; + while (isdigit(it8->ch)) { + + cmsInt32Number digit = (it8->ch - '0'); + + if ((cmsFloat64Number)e * 10.0 + (cmsFloat64Number)digit < (cmsFloat64Number)+2147483647.0) + e = e * 10 + digit; + + NextCh(it8); + } + + e = sgn*e; + it8->dnum = it8->dnum * xpow10(e); + } +} + +// Parses a float number +// This can not call directly atof because it uses locale dependent +// parsing, while CCMX files always use . as decimal separator +static +cmsFloat64Number ParseFloatNumber(const char *Buffer) +{ + cmsFloat64Number dnum = 0.0; + int sign = 1; + + // keep safe + if (Buffer == NULL) return 0.0; + + if (*Buffer == '-' || *Buffer == '+') { + + sign = (*Buffer == '-') ? -1 : 1; + Buffer++; + } + + + while (*Buffer && isdigit((int)*Buffer)) { + + dnum = dnum * 10.0 + (*Buffer - '0'); + if (*Buffer) Buffer++; + } + + if (*Buffer == '.') { + + cmsFloat64Number frac = 0.0; // fraction + int prec = 0; // precision + + if (*Buffer) Buffer++; + + while (*Buffer && isdigit((int)*Buffer)) { + + frac = frac * 10.0 + (*Buffer - '0'); + prec++; + if (*Buffer) Buffer++; + } + + dnum = dnum + (frac / xpow10(prec)); + } + + // Exponent, example 34.00E+20 + if (*Buffer && toupper(*Buffer) == 'E') { + + int e; + int sgn; + + if (*Buffer) Buffer++; + sgn = 1; + + if (*Buffer == '-') { + + sgn = -1; + if (*Buffer) Buffer++; + } + else + if (*Buffer == '+') { + + sgn = +1; + if (*Buffer) Buffer++; + } + + e = 0; + while (*Buffer && isdigit((int)*Buffer)) { + + cmsInt32Number digit = (*Buffer - '0'); + + if ((cmsFloat64Number)e * 10.0 + digit < (cmsFloat64Number)+2147483647.0) + e = e * 10 + digit; + + if (*Buffer) Buffer++; + } + + e = sgn*e; + dnum = dnum * xpow10(e); + } + + return sign * dnum; +} + + +// Reads next symbol +static +void InSymbol(cmsIT8* it8) +{ + CMSREGISTER char *idptr; + CMSREGISTER int k; + SYMBOL key; + int sng; + + do { + + while (isseparator(it8->ch)) + NextCh(it8); + + if (isfirstidchar(it8->ch)) { // Identifier + + k = 0; + idptr = it8->id; + + do { + + if (++k < MAXID) *idptr++ = (char) it8->ch; + + NextCh(it8); + + } while (isidchar(it8->ch)); + + *idptr = '\0'; + + + key = BinSrchKey(it8->id); + if (key == SUNDEFINED) it8->sy = SIDENT; + else it8->sy = key; + + } + else // Is a number? + if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+') + { + int sign = 1; + + if (it8->ch == '-') { + sign = -1; + NextCh(it8); + } + + it8->inum = 0; + it8->sy = SINUM; + + if (it8->ch == '0') { // 0xnnnn (Hexa) or 0bnnnn (Binary) + + NextCh(it8); + if (toupper(it8->ch) == 'X') { + + int j; + + NextCh(it8); + while (isxdigit(it8->ch)) + { + it8->ch = toupper(it8->ch); + if (it8->ch >= 'A' && it8->ch <= 'F') j = it8->ch -'A'+10; + else j = it8->ch - '0'; + + if ((cmsFloat64Number) it8->inum * 16.0 + (cmsFloat64Number) j > (cmsFloat64Number)+2147483647.0) + { + SynError(it8, "Invalid hexadecimal number"); + return; + } + + it8->inum = it8->inum * 16 + j; + NextCh(it8); + } + return; + } + + if (toupper(it8->ch) == 'B') { // Binary + + int j; + + NextCh(it8); + while (it8->ch == '0' || it8->ch == '1') + { + j = it8->ch - '0'; + + if ((cmsFloat64Number) it8->inum * 2.0 + j > (cmsFloat64Number)+2147483647.0) + { + SynError(it8, "Invalid binary number"); + return; + } + + it8->inum = it8->inum * 2 + j; + NextCh(it8); + } + return; + } + } + + + while (isdigit(it8->ch)) { + + cmsInt32Number digit = (it8->ch - '0'); + + if ((cmsFloat64Number) it8->inum * 10.0 + (cmsFloat64Number) digit > (cmsFloat64Number) +2147483647.0) { + ReadReal(it8, it8->inum); + it8->sy = SDNUM; + it8->dnum *= sign; + return; + } + + it8->inum = it8->inum * 10 + digit; + NextCh(it8); + } + + if (it8->ch == '.') { + + ReadReal(it8, it8->inum); + it8->sy = SDNUM; + it8->dnum *= sign; + return; + } + + it8 -> inum *= sign; + + // Special case. Numbers followed by letters are taken as identifiers + + if (isidchar(it8 ->ch)) { + + if (it8 ->sy == SINUM) { + + snprintf(it8->id, 127, "%d", it8->inum); + } + else { + + snprintf(it8->id, 127, it8 ->DoubleFormatter, it8->dnum); + } + + k = (int) strlen(it8 ->id); + idptr = it8 ->id + k; + do { + + if (++k < MAXID) *idptr++ = (char) it8->ch; + + NextCh(it8); + + } while (isidchar(it8->ch)); + + *idptr = '\0'; + it8->sy = SIDENT; + } + return; + + } + else + switch ((int) it8->ch) { + + // EOF marker -- ignore it + case '\x1a': + NextCh(it8); + break; + + // Eof stream markers + case 0: + case -1: + it8->sy = SEOF; + break; + + + // Next line + case '\r': + NextCh(it8); + if (it8 ->ch == '\n') + NextCh(it8); + it8->sy = SEOLN; + it8->lineno++; + break; + + case '\n': + NextCh(it8); + it8->sy = SEOLN; + it8->lineno++; + break; + + // Comment + case '#': + NextCh(it8); + while (it8->ch && it8->ch != '\n' && it8->ch != '\r') + NextCh(it8); + + it8->sy = SCOMMENT; + break; + + // String. + case '\'': + case '\"': + idptr = it8->str; + sng = it8->ch; + k = 0; + NextCh(it8); + + while (k < (MAXSTR-1) && it8->ch != sng) { + + if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1; + else { + *idptr++ = (char) it8->ch; + NextCh(it8); + k++; + } + } + + it8->sy = SSTRING; + *idptr = '\0'; + NextCh(it8); + break; + + + default: + SynError(it8, "Unrecognized character: 0x%x", it8 ->ch); + return; + } + + } while (it8->sy == SCOMMENT); + + // Handle the include special token + + if (it8 -> sy == SINCLUDE) { + + FILECTX* FileNest; + + if(it8 -> IncludeSP >= (MAXINCLUDE-1)) { + + SynError(it8, "Too many recursion levels"); + return; + } + + InSymbol(it8); + if (!Check(it8, SSTRING, "Filename expected")) return; + + FileNest = it8 -> FileStack[it8 -> IncludeSP + 1]; + if(FileNest == NULL) { + + FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX)); + //if(FileNest == NULL) + // TODO: how to manage out-of-memory conditions? + } + + if (BuildAbsolutePath(it8->str, + it8->FileStack[it8->IncludeSP]->FileName, + FileNest->FileName, cmsMAX_PATH-1) == FALSE) { + SynError(it8, "File path too long"); + return; + } + + FileNest->Stream = fopen(FileNest->FileName, "rt"); + if (FileNest->Stream == NULL) { + + SynError(it8, "File %s not found", FileNest->FileName); + return; + } + it8->IncludeSP++; + + it8 ->ch = ' '; + InSymbol(it8); + } + +} + +// Checks end of line separator +static +cmsBool CheckEOLN(cmsIT8* it8) +{ + if (!Check(it8, SEOLN, "Expected separator")) return FALSE; + while (it8 -> sy == SEOLN) + InSymbol(it8); + return TRUE; + +} + +// Skip a symbol + +static +void Skip(cmsIT8* it8, SYMBOL sy) +{ + if (it8->sy == sy && it8->sy != SEOF) + InSymbol(it8); +} + + +// Skip multiple EOLN +static +void SkipEOLN(cmsIT8* it8) +{ + while (it8->sy == SEOLN) { + InSymbol(it8); + } +} + + +// Returns a string holding current value +static +cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* ErrorTitle) +{ + switch (it8->sy) { + + case SEOLN: // Empty value + Buffer[0]=0; + break; + case SIDENT: strncpy(Buffer, it8->id, max); + Buffer[max-1]=0; + break; + case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break; + case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break; + case SSTRING: strncpy(Buffer, it8->str, max); + Buffer[max-1] = 0; + break; + + + default: + return SynError(it8, "%s", ErrorTitle); + } + + Buffer[max] = 0; + return TRUE; +} + +// ---------------------------------------------------------- Table + +static +TABLE* GetTable(cmsIT8* it8) +{ + if ((it8 -> nTable >= it8 ->TablesCount)) { + + SynError(it8, "Table %d out of sequence", it8 -> nTable); + return it8 -> Tab; + } + + return it8 ->Tab + it8 ->nTable; +} + +// ---------------------------------------------------------- Memory management + + +// Frees an allocator and owned memory +void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + if (it8 == NULL) + return; + + if (it8->MemorySink) { + + OWNEDMEM* p; + OWNEDMEM* n; + + for (p = it8->MemorySink; p != NULL; p = n) { + + n = p->Next; + if (p->Ptr) _cmsFree(it8 ->ContextID, p->Ptr); + _cmsFree(it8 ->ContextID, p); + } + } + + if (it8->MemoryBlock) + _cmsFree(it8 ->ContextID, it8->MemoryBlock); + + _cmsFree(it8 ->ContextID, it8); +} + + +// Allocates a chunk of data, keep linked list +static +void* AllocBigBlock(cmsIT8* it8, cmsUInt32Number size) +{ + OWNEDMEM* ptr1; + void* ptr = _cmsMallocZero(it8->ContextID, size); + + if (ptr != NULL) { + + ptr1 = (OWNEDMEM*) _cmsMallocZero(it8 ->ContextID, sizeof(OWNEDMEM)); + + if (ptr1 == NULL) { + + _cmsFree(it8 ->ContextID, ptr); + return NULL; + } + + ptr1-> Ptr = ptr; + ptr1-> Next = it8 -> MemorySink; + it8 -> MemorySink = ptr1; + } + + return ptr; +} + + +// Suballocator. +static +void* AllocChunk(cmsIT8* it8, cmsUInt32Number size) +{ + cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used; + cmsUInt8Number* ptr; + + size = _cmsALIGNMEM(size); + + if (size > Free) { + + if (it8 -> Allocator.BlockSize == 0) + + it8 -> Allocator.BlockSize = 20*1024; + else + it8 ->Allocator.BlockSize *= 2; + + if (it8 ->Allocator.BlockSize < size) + it8 ->Allocator.BlockSize = size; + + it8 ->Allocator.Used = 0; + it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize); + } + + ptr = it8 ->Allocator.Block + it8 ->Allocator.Used; + it8 ->Allocator.Used += size; + + return (void*) ptr; + +} + + +// Allocates a string +static +char *AllocString(cmsIT8* it8, const char* str) +{ + cmsUInt32Number Size = (cmsUInt32Number) strlen(str)+1; + char *ptr; + + + ptr = (char *) AllocChunk(it8, Size); + if (ptr) strncpy (ptr, str, Size-1); + + return ptr; +} + +// Searches through linked list + +static +cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYVALUE** LastPtr) +{ + if (LastPtr) *LastPtr = p; + + for (; p != NULL; p = p->Next) { + + if (LastPtr) *LastPtr = p; + + if (*Key != '#') { // Comments are ignored + + if (cmsstrcasecmp(Key, p->Keyword) == 0) + break; + } + } + + if (p == NULL) + return FALSE; + + if (Subkey == 0) + return TRUE; + + for (; p != NULL; p = p->NextSubkey) { + + if (p ->Subkey == NULL) continue; + + if (LastPtr) *LastPtr = p; + + if (cmsstrcasecmp(Subkey, p->Subkey) == 0) + return TRUE; + } + + return FALSE; +} + + + +// Add a property into a linked list +static +KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs) +{ + KEYVALUE* p; + KEYVALUE* last; + + + // Check if property is already in list + + if (IsAvailableOnList(*Head, Key, Subkey, &p)) { + + // This may work for editing properties + + // return SynError(it8, "duplicate key <%s>", Key); + } + else { + + last = p; + + // Allocate the container + p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE)); + if (p == NULL) + { + SynError(it8, "AddToList: out of memory"); + return NULL; + } + + // Store name and value + p->Keyword = AllocString(it8, Key); + p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey); + + // Keep the container in our list + if (*Head == NULL) { + *Head = p; + } + else + { + if (Subkey != NULL && last != NULL) { + + last->NextSubkey = p; + + // If Subkey is not null, then last is the last property with the same key, + // but not necessarily is the last property in the list, so we need to move + // to the actual list end + while (last->Next != NULL) + last = last->Next; + } + + if (last != NULL) last->Next = p; + } + + p->Next = NULL; + p->NextSubkey = NULL; + } + + p->WriteAs = WriteAs; + + if (xValue != NULL) { + + p->Value = AllocString(it8, xValue); + } + else { + p->Value = NULL; + } + + return p; +} + +static +KEYVALUE* AddAvailableProperty(cmsIT8* it8, const char* Key, WRITEMODE as) +{ + return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as); +} + + +static +KEYVALUE* AddAvailableSampleID(cmsIT8* it8, const char* Key) +{ + return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED); +} + + +static +void AllocTable(cmsIT8* it8) +{ + TABLE* t; + + t = it8 ->Tab + it8 ->TablesCount; + + t->HeaderList = NULL; + t->DataFormat = NULL; + t->Data = NULL; + + it8 ->TablesCount++; +} + + +cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable) +{ + cmsIT8* it8 = (cmsIT8*) IT8; + + if (nTable >= it8 ->TablesCount) { + + if (nTable == it8 ->TablesCount) { + + AllocTable(it8); + } + else { + SynError(it8, "Table %d is out of sequence", nTable); + return -1; + } + } + + it8 ->nTable = nTable; + + return (cmsInt32Number) nTable; +} + + + +// Init an empty container +cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) +{ + cmsIT8* it8; + cmsUInt32Number i; + + it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8)); + if (it8 == NULL) return NULL; + + AllocTable(it8); + + it8->MemoryBlock = NULL; + it8->MemorySink = NULL; + + it8 ->nTable = 0; + + it8->ContextID = ContextID; + it8->Allocator.Used = 0; + it8->Allocator.Block = NULL; + it8->Allocator.BlockSize = 0; + + it8->ValidKeywords = NULL; + it8->ValidSampleID = NULL; + + it8 -> sy = SUNDEFINED; + it8 -> ch = ' '; + it8 -> Source = NULL; + it8 -> inum = 0; + it8 -> dnum = 0.0; + + it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX)); + it8->IncludeSP = 0; + it8 -> lineno = 1; + + strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); + cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17"); + + // Initialize predefined properties & data + + for (i=0; i < NUMPREDEFINEDPROPS; i++) + AddAvailableProperty(it8, PredefinedProperties[i].id, PredefinedProperties[i].as); + + for (i=0; i < NUMPREDEFINEDSAMPLEID; i++) + AddAvailableSampleID(it8, PredefinedSampleID[i]); + + + return (cmsHANDLE) it8; +} + + +const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8) +{ + return GetTable((cmsIT8*) hIT8)->SheetType; +} + +cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type) +{ + TABLE* t = GetTable((cmsIT8*) hIT8); + + strncpy(t ->SheetType, Type, MAXSTR-1); + t ->SheetType[MAXSTR-1] = 0; + return TRUE; +} + +cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + if (!Val) return FALSE; + if (!*Val) return FALSE; + + return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL; +} + +// Sets a property +cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + if (!Val) return FALSE; + if (!*Val) return FALSE; + + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL; +} + +cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buffer[1024]; + + snprintf(Buffer, 1023, it8->DoubleFormatter, Val); + + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; +} + +cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buffer[1024]; + + snprintf(Buffer, 1023, "%u", Val); + + return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; +} + +cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL; +} + +cmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL; +} + +// Gets a property +const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* Key) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + KEYVALUE* p; + + if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p)) + { + return p -> Value; + } + return NULL; +} + + +cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp) +{ + const char *v = cmsIT8GetProperty(hIT8, cProp); + + if (v == NULL) return 0.0; + + return ParseFloatNumber(v); +} + +const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + KEYVALUE* p; + + if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) { + return p -> Value; + } + return NULL; +} + +// ----------------------------------------------------------------- Datasets + + +static +void AllocateDataFormat(cmsIT8* it8) +{ + TABLE* t = GetTable(it8); + + if (t -> DataFormat) return; // Already allocated + + t -> nSamples = (int) cmsIT8GetPropertyDbl(it8, "NUMBER_OF_FIELDS"); + + if (t -> nSamples <= 0) { + + SynError(it8, "AllocateDataFormat: Unknown NUMBER_OF_FIELDS"); + t -> nSamples = 10; + } + + t -> DataFormat = (char**) AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * sizeof(char *)); + if (t->DataFormat == NULL) { + + SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array"); + } + +} + +static +const char *GetDataFormat(cmsIT8* it8, int n) +{ + TABLE* t = GetTable(it8); + + if (t->DataFormat) + return t->DataFormat[n]; + + return NULL; +} + +static +cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label) +{ + TABLE* t = GetTable(it8); + + if (!t->DataFormat) + AllocateDataFormat(it8); + + if (n > t -> nSamples) { + SynError(it8, "More than NUMBER_OF_FIELDS fields."); + return FALSE; + } + + if (t->DataFormat) { + t->DataFormat[n] = AllocString(it8, label); + } + + return TRUE; +} + + +cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE h, int n, const char *Sample) +{ + cmsIT8* it8 = (cmsIT8*)h; + return SetDataFormat(it8, n, Sample); +} + +// A safe atoi that returns 0 when NULL input is given +static +cmsInt32Number satoi(const char* b) +{ + if (b == NULL) return 0; + return atoi(b); +} + +static +void AllocateDataSet(cmsIT8* it8) +{ + TABLE* t = GetTable(it8); + + if (t -> Data) return; // Already allocated + + t-> nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); + t-> nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); + + if (t -> nSamples < 0 || t->nSamples > 0x7ffe || t->nPatches < 0 || t->nPatches > 0x7ffe) + { + SynError(it8, "AllocateDataSet: too much data"); + } + else { + // Some dumb analizers warns of possible overflow here, just take a look couple of lines above. + t->Data = (char**)AllocChunk(it8, ((cmsUInt32Number)t->nSamples + 1) * ((cmsUInt32Number)t->nPatches + 1) * sizeof(char*)); + if (t->Data == NULL) { + + SynError(it8, "AllocateDataSet: Unable to allocate data array"); + } + } + +} + +static +char* GetData(cmsIT8* it8, int nSet, int nField) +{ + TABLE* t = GetTable(it8); + int nSamples = t -> nSamples; + int nPatches = t -> nPatches; + + if (nSet >= nPatches || nField >= nSamples) + return NULL; + + if (!t->Data) return NULL; + return t->Data [nSet * nSamples + nField]; +} + +static +cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val) +{ + TABLE* t = GetTable(it8); + + if (!t->Data) + AllocateDataSet(it8); + + if (!t->Data) return FALSE; + + if (nSet > t -> nPatches || nSet < 0) { + + return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches); + } + + if (nField > t ->nSamples || nField < 0) { + return SynError(it8, "Sample %d out of range, there are %d samples", nField, t ->nSamples); + + } + + t->Data [nSet * t -> nSamples + nField] = AllocString(it8, Val); + return TRUE; +} + + +// --------------------------------------------------------------- File I/O + + +// Writes a string to file +static +void WriteStr(SAVESTREAM* f, const char *str) +{ + cmsUInt32Number len; + + if (str == NULL) + str = " "; + + // Length to write + len = (cmsUInt32Number) strlen(str); + f ->Used += len; + + + if (f ->stream) { // Should I write it to a file? + + if (fwrite(str, 1, len, f->stream) != len) { + cmsSignalError(0, cmsERROR_WRITE, "Write to file error in CGATS parser"); + return; + } + + } + else { // Or to a memory block? + + if (f ->Base) { // Am I just counting the bytes? + + if (f ->Used > f ->Max) { + + cmsSignalError(0, cmsERROR_WRITE, "Write to memory overflows in CGATS parser"); + return; + } + + memmove(f ->Ptr, str, len); + f->Ptr += len; + } + + } +} + + +// Write formatted + +static +void Writef(SAVESTREAM* f, const char* frm, ...) +{ + char Buffer[4096]; + va_list args; + + va_start(args, frm); + vsnprintf(Buffer, 4095, frm, args); + Buffer[4095] = 0; + WriteStr(f, Buffer); + va_end(args); + +} + +// Writes full header +static +void WriteHeader(cmsIT8* it8, SAVESTREAM* fp) +{ + KEYVALUE* p; + TABLE* t = GetTable(it8); + + // Writes the type + WriteStr(fp, t->SheetType); + WriteStr(fp, "\n"); + + for (p = t->HeaderList; (p != NULL); p = p->Next) + { + if (*p ->Keyword == '#') { + + char* Pt; + + WriteStr(fp, "#\n# "); + for (Pt = p ->Value; *Pt; Pt++) { + + + Writef(fp, "%c", *Pt); + + if (*Pt == '\n') { + WriteStr(fp, "# "); + } + } + + WriteStr(fp, "\n#\n"); + continue; + } + + + if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) { + +#ifdef CMS_STRICT_CGATS + WriteStr(fp, "KEYWORD\t\""); + WriteStr(fp, p->Keyword); + WriteStr(fp, "\"\n"); +#endif + + AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED); + } + + WriteStr(fp, p->Keyword); + if (p->Value) { + + switch (p ->WriteAs) { + + case WRITE_UNCOOKED: + Writef(fp, "\t%s", p ->Value); + break; + + case WRITE_STRINGIFY: + Writef(fp, "\t\"%s\"", p->Value ); + break; + + case WRITE_HEXADECIMAL: + Writef(fp, "\t0x%X", satoi(p ->Value)); + break; + + case WRITE_BINARY: + Writef(fp, "\t0x%B", satoi(p ->Value)); + break; + + case WRITE_PAIR: + Writef(fp, "\t\"%s,%s\"", p->Subkey, p->Value); + break; + + default: SynError(it8, "Unknown write mode %d", p ->WriteAs); + return; + } + } + + WriteStr (fp, "\n"); + } + +} + + +// Writes the data format +static +void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8) +{ + int i, nSamples; + TABLE* t = GetTable(it8); + + if (!t -> DataFormat) return; + + WriteStr(fp, "BEGIN_DATA_FORMAT\n"); + WriteStr(fp, " "); + nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); + + for (i = 0; i < nSamples; i++) { + + WriteStr(fp, t->DataFormat[i]); + WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t")); + } + + WriteStr (fp, "END_DATA_FORMAT\n"); +} + + +// Writes data array +static +void WriteData(SAVESTREAM* fp, cmsIT8* it8) +{ + int i, j; + TABLE* t = GetTable(it8); + + if (!t->Data) return; + + WriteStr (fp, "BEGIN_DATA\n"); + + t->nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); + + for (i = 0; i < t-> nPatches; i++) { + + WriteStr(fp, " "); + + for (j = 0; j < t->nSamples; j++) { + + char *ptr = t->Data[i*t->nSamples+j]; + + if (ptr == NULL) WriteStr(fp, "\"\""); + else { + // If value contains whitespace, enclose within quote + + if (strchr(ptr, ' ') != NULL) { + + WriteStr(fp, "\""); + WriteStr(fp, ptr); + WriteStr(fp, "\""); + } + else + WriteStr(fp, ptr); + } + + WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t")); + } + } + WriteStr (fp, "END_DATA\n"); +} + + + +// Saves whole file +cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) +{ + SAVESTREAM sd; + cmsUInt32Number i; + cmsIT8* it8 = (cmsIT8*) hIT8; + + memset(&sd, 0, sizeof(sd)); + + sd.stream = fopen(cFileName, "wt"); + if (!sd.stream) return FALSE; + + for (i=0; i < it8 ->TablesCount; i++) { + + cmsIT8SetTable(hIT8, i); + WriteHeader(it8, &sd); + WriteDataFormat(&sd, it8); + WriteData(&sd, it8); + } + + if (fclose(sd.stream) != 0) return FALSE; + + return TRUE; +} + + +// Saves to memory +cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded) +{ + SAVESTREAM sd; + cmsUInt32Number i; + cmsIT8* it8 = (cmsIT8*) hIT8; + + memset(&sd, 0, sizeof(sd)); + + sd.stream = NULL; + sd.Base = (cmsUInt8Number*) MemPtr; + sd.Ptr = sd.Base; + + sd.Used = 0; + + if (sd.Base) + sd.Max = *BytesNeeded; // Write to memory? + else + sd.Max = 0; // Just counting the needed bytes + + for (i=0; i < it8 ->TablesCount; i++) { + + cmsIT8SetTable(hIT8, i); + WriteHeader(it8, &sd); + WriteDataFormat(&sd, it8); + WriteData(&sd, it8); + } + + sd.Used++; // The \0 at the very end + + if (sd.Base) + *sd.Ptr = 0; + + *BytesNeeded = sd.Used; + + return TRUE; +} + + +// -------------------------------------------------------------- Higher level parsing + +static +cmsBool DataFormatSection(cmsIT8* it8) +{ + int iField = 0; + TABLE* t = GetTable(it8); + + InSymbol(it8); // Eats "BEGIN_DATA_FORMAT" + CheckEOLN(it8); + + while (it8->sy != SEND_DATA_FORMAT && + it8->sy != SEOLN && + it8->sy != SEOF && + it8->sy != SSYNERROR) { + + if (it8->sy != SIDENT) { + + return SynError(it8, "Sample type expected"); + } + + if (!SetDataFormat(it8, iField, it8->id)) return FALSE; + iField++; + + InSymbol(it8); + SkipEOLN(it8); + } + + SkipEOLN(it8); + Skip(it8, SEND_DATA_FORMAT); + SkipEOLN(it8); + + if (iField != t ->nSamples) { + SynError(it8, "Count mismatch. NUMBER_OF_FIELDS was %d, found %d\n", t ->nSamples, iField); + + + } + + return TRUE; +} + + + +static +cmsBool DataSection (cmsIT8* it8) +{ + int iField = 0; + int iSet = 0; + char Buffer[256]; + TABLE* t = GetTable(it8); + + InSymbol(it8); // Eats "BEGIN_DATA" + CheckEOLN(it8); + + if (!t->Data) + AllocateDataSet(it8); + + while (it8->sy != SEND_DATA && it8->sy != SEOF) + { + if (iField >= t -> nSamples) { + iField = 0; + iSet++; + + } + + if (it8->sy != SEND_DATA && it8->sy != SEOF) { + + if (!GetVal(it8, Buffer, 255, "Sample data expected")) + return FALSE; + + if (!SetData(it8, iSet, iField, Buffer)) + return FALSE; + + iField++; + + InSymbol(it8); + SkipEOLN(it8); + } + } + + SkipEOLN(it8); + Skip(it8, SEND_DATA); + SkipEOLN(it8); + + // Check for data completion. + + if ((iSet+1) != t -> nPatches) + return SynError(it8, "Count mismatch. NUMBER_OF_SETS was %d, found %d\n", t ->nPatches, iSet+1); + + return TRUE; +} + + + + +static +cmsBool HeaderSection(cmsIT8* it8) +{ + char VarName[MAXID]; + char Buffer[MAXSTR]; + KEYVALUE* Key; + + while (it8->sy != SEOF && + it8->sy != SSYNERROR && + it8->sy != SBEGIN_DATA_FORMAT && + it8->sy != SBEGIN_DATA) { + + + switch (it8 -> sy) { + + case SKEYWORD: + InSymbol(it8); + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE; + InSymbol(it8); + break; + + + case SDATA_FORMAT_ID: + InSymbol(it8); + if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; + if (!AddAvailableSampleID(it8, Buffer)) return FALSE; + InSymbol(it8); + break; + + + case SIDENT: + strncpy(VarName, it8->id, MAXID - 1); + VarName[MAXID - 1] = 0; + + if (!IsAvailableOnList(it8->ValidKeywords, VarName, NULL, &Key)) { + +#ifdef CMS_STRICT_CGATS + return SynError(it8, "Undefined keyword '%s'", VarName); +#else + Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED); + if (Key == NULL) return FALSE; +#endif + } + + InSymbol(it8); + if (!GetVal(it8, Buffer, MAXSTR - 1, "Property data expected")) return FALSE; + + if (Key->WriteAs != WRITE_PAIR) { + AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer, + (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); + } + else { + const char *Subkey; + char *Nextkey; + if (it8->sy != SSTRING) + return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName); + + // chop the string as a list of "subkey, value" pairs, using ';' as a separator + for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey) + { + char *Value, *temp; + + // identify token pair boundary + Nextkey = (char*)strchr(Subkey, ';'); + if (Nextkey) + *Nextkey++ = '\0'; + + // for each pair, split the subkey and the value + Value = (char*)strrchr(Subkey, ','); + if (Value == NULL) + return SynError(it8, "Invalid value for property '%s'.", VarName); + + // gobble the spaces before the coma, and the coma itself + temp = Value++; + do *temp-- = '\0'; while (temp >= Subkey && *temp == ' '); + + // gobble any space at the right + temp = Value + strlen(Value) - 1; + while (*temp == ' ') *temp-- = '\0'; + + // trim the strings from the left + Subkey += strspn(Subkey, " "); + Value += strspn(Value, " "); + + if (Subkey[0] == 0 || Value[0] == 0) + return SynError(it8, "Invalid value for property '%s'.", VarName); + AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR); + } + } + + InSymbol(it8); + break; + + + case SEOLN: break; + + default: + return SynError(it8, "expected keyword or identifier"); + } + + SkipEOLN(it8); + } + + return TRUE; + +} + + +static +void ReadType(cmsIT8* it8, char* SheetTypePtr) +{ + cmsInt32Number cnt = 0; + + // First line is a very special case. + + while (isseparator(it8->ch)) + NextCh(it8); + + while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != 0) { + + if (cnt++ < MAXSTR) + *SheetTypePtr++= (char) it8 ->ch; + NextCh(it8); + } + + *SheetTypePtr = 0; +} + + +static +cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) +{ + char* SheetTypePtr = it8 ->Tab[0].SheetType; + + if (nosheet == 0) { + ReadType(it8, SheetTypePtr); + } + + InSymbol(it8); + + SkipEOLN(it8); + + while (it8-> sy != SEOF && + it8-> sy != SSYNERROR) { + + switch (it8 -> sy) { + + case SBEGIN_DATA_FORMAT: + if (!DataFormatSection(it8)) return FALSE; + break; + + case SBEGIN_DATA: + + if (!DataSection(it8)) return FALSE; + + if (it8 -> sy != SEOF) { + + AllocTable(it8); + it8 ->nTable = it8 ->TablesCount - 1; + + // Read sheet type if present. We only support identifier and string. + // is a type string + // anything else, is not a type string + if (nosheet == 0) { + + if (it8 ->sy == SIDENT) { + + // May be a type sheet or may be a prop value statement. We cannot use insymbol in + // this special case... + while (isseparator(it8->ch)) + NextCh(it8); + + // If a newline is found, then this is a type string + if (it8 ->ch == '\n' || it8->ch == '\r') { + + cmsIT8SetSheetType(it8, it8 ->id); + InSymbol(it8); + } + else + { + // It is not. Just continue + cmsIT8SetSheetType(it8, ""); + } + } + else + // Validate quoted strings + if (it8 ->sy == SSTRING) { + cmsIT8SetSheetType(it8, it8 ->str); + InSymbol(it8); + } + } + + } + break; + + case SEOLN: + SkipEOLN(it8); + break; + + default: + if (!HeaderSection(it8)) return FALSE; + } + + } + + return (it8 -> sy != SSYNERROR); +} + + + +// Init useful pointers + +static +void CookPointers(cmsIT8* it8) +{ + int idField, i; + char* Fld; + cmsUInt32Number j; + cmsUInt32Number nOldTable = it8 ->nTable; + + for (j=0; j < it8 ->TablesCount; j++) { + + TABLE* t = it8 ->Tab + j; + + t -> SampleID = 0; + it8 ->nTable = j; + + for (idField = 0; idField < t -> nSamples; idField++) + { + if (t ->DataFormat == NULL){ + SynError(it8, "Undefined DATA_FORMAT"); + return; + } + + Fld = t->DataFormat[idField]; + if (!Fld) continue; + + + if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { + + t -> SampleID = idField; + } + + // "LABEL" is an extension. It keeps references to forward tables + + if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') { + + // Search for table references... + for (i = 0; i < t->nPatches; i++) { + + char* Label = GetData(it8, i, idField); + + if (Label) { + + cmsUInt32Number k; + + // This is the label, search for a table containing + // this property + + for (k = 0; k < it8->TablesCount; k++) { + + TABLE* Table = it8->Tab + k; + KEYVALUE* p; + + if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { + + // Available, keep type and table + char Buffer[256]; + + char* Type = p->Value; + int nTable = (int)k; + + snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type); + + SetData(it8, i, idField, Buffer); + } + } + + + } + + } + + + } + + } + } + + it8 ->nTable = nOldTable; +} + +// Try to infere if the file is a CGATS/IT8 file at all. Read first line +// that should be something like some printable characters plus a \n +// returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line? +static +int IsMyBlock(const cmsUInt8Number* Buffer, cmsUInt32Number n) +{ + int words = 1, space = 0, quot = 0; + cmsUInt32Number i; + + if (n < 10) return 0; // Too small + + if (n > 132) + n = 132; + + for (i = 1; i < n; i++) { + + switch(Buffer[i]) + { + case '\n': + case '\r': + return ((quot == 1) || (words > 2)) ? 0 : words; + case '\t': + case ' ': + if(!quot && !space) + space = 1; + break; + case '\"': + quot = !quot; + break; + default: + if (Buffer[i] < 32) return 0; + if (Buffer[i] > 127) return 0; + words += space; + space = 0; + break; + } + } + + return 0; +} + + +static +cmsBool IsMyFile(const char* FileName) +{ + FILE *fp; + cmsUInt32Number Size; + cmsUInt8Number Ptr[133]; + + fp = fopen(FileName, "rt"); + if (!fp) { + cmsSignalError(0, cmsERROR_FILE, "File '%s' not found", FileName); + return FALSE; + } + + Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp); + + if (fclose(fp) != 0) + return FALSE; + + Ptr[Size] = '\0'; + + return IsMyBlock(Ptr, Size); +} + +// ---------------------------------------------------------- Exported routines + + +cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cmsUInt32Number len) +{ + cmsHANDLE hIT8; + cmsIT8* it8; + int type; + + _cmsAssert(Ptr != NULL); + _cmsAssert(len != 0); + + type = IsMyBlock((const cmsUInt8Number*)Ptr, len); + if (type == 0) return NULL; + + hIT8 = cmsIT8Alloc(ContextID); + if (!hIT8) return NULL; + + it8 = (cmsIT8*) hIT8; + it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1); + if (it8->MemoryBlock == NULL) + { + cmsIT8Free(hIT8); + return FALSE; + } + + strncpy(it8 ->MemoryBlock, (const char*) Ptr, len); + it8 ->MemoryBlock[len] = 0; + + strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1); + it8-> Source = it8 -> MemoryBlock; + + if (!ParseIT8(it8, type-1)) { + + cmsIT8Free(hIT8); + return FALSE; + } + + CookPointers(it8); + it8 ->nTable = 0; + + _cmsFree(ContextID, it8->MemoryBlock); + it8 -> MemoryBlock = NULL; + + return hIT8; + + +} + + +cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName) +{ + + cmsHANDLE hIT8; + cmsIT8* it8; + int type; + + _cmsAssert(cFileName != NULL); + + type = IsMyFile(cFileName); + if (type == 0) return NULL; + + hIT8 = cmsIT8Alloc(ContextID); + it8 = (cmsIT8*) hIT8; + if (!hIT8) return NULL; + + + it8 ->FileStack[0]->Stream = fopen(cFileName, "rt"); + + if (!it8 ->FileStack[0]->Stream) { + cmsIT8Free(hIT8); + return NULL; + } + + + strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1); + it8->FileStack[0]->FileName[cmsMAX_PATH-1] = 0; + + if (!ParseIT8(it8, type-1)) { + + fclose(it8 ->FileStack[0]->Stream); + cmsIT8Free(hIT8); + return NULL; + } + + CookPointers(it8); + it8 ->nTable = 0; + + if (fclose(it8 ->FileStack[0]->Stream)!= 0) { + cmsIT8Free(hIT8); + return NULL; + } + + return hIT8; + +} + +int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + TABLE* t; + + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); + + if (SampleNames) + *SampleNames = t -> DataFormat; + return t -> nSamples; +} + + +cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + KEYVALUE* p; + cmsUInt32Number n; + char **Props; + TABLE* t; + + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); + + // Pass#1 - count properties + + n = 0; + for (p = t -> HeaderList; p != NULL; p = p->Next) { + n++; + } + + + Props = (char **) AllocChunk(it8, sizeof(char *) * n); + + // Pass#2 - Fill pointers + n = 0; + for (p = t -> HeaderList; p != NULL; p = p->Next) { + Props[n++] = p -> Keyword; + } + + *PropertyNames = Props; + return n; +} + +cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + KEYVALUE *p, *tmp; + cmsUInt32Number n; + const char **Props; + TABLE* t; + + _cmsAssert(hIT8 != NULL); + + + t = GetTable(it8); + + if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) { + *SubpropertyNames = 0; + return 0; + } + + // Pass#1 - count properties + + n = 0; + for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { + if(tmp->Subkey != NULL) + n++; + } + + + Props = (const char **) AllocChunk(it8, sizeof(char *) * n); + + // Pass#2 - Fill pointers + n = 0; + for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { + if(tmp->Subkey != NULL) + Props[n++] = p ->Subkey; + } + + *SubpropertyNames = Props; + return n; +} + +static +int LocatePatch(cmsIT8* it8, const char* cPatch) +{ + int i; + const char *data; + TABLE* t = GetTable(it8); + + for (i=0; i < t-> nPatches; i++) { + + data = GetData(it8, i, t->SampleID); + + if (data != NULL) { + + if (cmsstrcasecmp(data, cPatch) == 0) + return i; + } + } + + // SynError(it8, "Couldn't find patch '%s'\n", cPatch); + return -1; +} + + +static +int LocateEmptyPatch(cmsIT8* it8) +{ + int i; + const char *data; + TABLE* t = GetTable(it8); + + for (i=0; i < t-> nPatches; i++) { + + data = GetData(it8, i, t->SampleID); + + if (data == NULL) + return i; + + } + + return -1; +} + +static +int LocateSample(cmsIT8* it8, const char* cSample) +{ + int i; + const char *fld; + TABLE* t = GetTable(it8); + + for (i=0; i < t->nSamples; i++) { + + fld = GetDataFormat(it8, i); + if (fld != NULL) { + if (cmsstrcasecmp(fld, cSample) == 0) + return i; + } + } + + return -1; + +} + + +int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + return LocateSample(it8, cSample); +} + + + +const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + return GetData(it8, row, col); +} + + +cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col) +{ + const char* Buffer; + + Buffer = cmsIT8GetDataRowCol(hIT8, row, col); + + if (Buffer == NULL) return 0.0; + + return ParseFloatNumber(Buffer); +} + + +cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const char* Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + return SetData(it8, row, col, Val); +} + + +cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFloat64Number Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buff[256]; + + _cmsAssert(hIT8 != NULL); + + snprintf(Buff, 255, it8->DoubleFormatter, Val); + + return SetData(it8, row, col, Buff); +} + + + +const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + int iField, iSet; + + _cmsAssert(hIT8 != NULL); + + iField = LocateSample(it8, cSample); + if (iField < 0) { + return NULL; + } + + iSet = LocatePatch(it8, cPatch); + if (iSet < 0) { + return NULL; + } + + return GetData(it8, iSet, iField); +} + + +cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch, const char* cSample) +{ + const char* Buffer; + + Buffer = cmsIT8GetData(it8, cPatch, cSample); + + return ParseFloatNumber(Buffer); +} + + + +cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + int iField, iSet; + TABLE* t; + + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); + + iField = LocateSample(it8, cSample); + + if (iField < 0) + return FALSE; + + if (t-> nPatches == 0) { + + AllocateDataFormat(it8); + AllocateDataSet(it8); + CookPointers(it8); + } + + if (cmsstrcasecmp(cSample, "SAMPLE_ID") == 0) { + + iSet = LocateEmptyPatch(it8); + if (iSet < 0) { + return SynError(it8, "Couldn't add more patches '%s'\n", cPatch); + } + + iField = t -> SampleID; + } + else { + iSet = LocatePatch(it8, cPatch); + if (iSet < 0) { + return FALSE; + } + } + + return SetData(it8, iSet, iField, Val); +} + + +cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch, + const char* cSample, + cmsFloat64Number Val) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + char Buff[256]; + + _cmsAssert(hIT8 != NULL); + + snprintf(Buff, 255, it8->DoubleFormatter, Val); + return cmsIT8SetData(hIT8, cPatch, cSample, Buff); +} + +// Buffer should get MAXSTR at least + +const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + TABLE* t; + char* Data; + + _cmsAssert(hIT8 != NULL); + + t = GetTable(it8); + Data = GetData(it8, nPatch, t->SampleID); + + if (!Data) return NULL; + if (!buffer) return Data; + + strncpy(buffer, Data, MAXSTR-1); + buffer[MAXSTR-1] = 0; + return buffer; +} + +int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch) +{ + _cmsAssert(hIT8 != NULL); + + return LocatePatch((cmsIT8*)hIT8, cPatch); +} + +cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + return it8 ->TablesCount; +} + +// This handles the "LABEL" extension. +// Label, nTable, Type + +int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType) +{ + const char* cLabelFld; + char Type[256], Label[256]; + cmsUInt32Number nTable; + + _cmsAssert(hIT8 != NULL); + + if (cField != NULL && *cField == 0) + cField = "LABEL"; + + if (cField == NULL) + cField = "LABEL"; + + cLabelFld = cmsIT8GetData(hIT8, cSet, cField); + if (!cLabelFld) return -1; + + if (sscanf(cLabelFld, "%255s %u %255s", Label, &nTable, Type) != 3) + return -1; + + if (ExpectedType != NULL && *ExpectedType == 0) + ExpectedType = NULL; + + if (ExpectedType) { + + if (cmsstrcasecmp(Type, ExpectedType) != 0) return -1; + } + + return cmsIT8SetTable(hIT8, nTable); +} + + +cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + int pos; + + _cmsAssert(hIT8 != NULL); + + pos = LocateSample(it8, cSample); + if(pos == -1) + return FALSE; + + it8->Tab[it8->nTable].SampleID = pos; + return TRUE; +} + + +void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) +{ + cmsIT8* it8 = (cmsIT8*) hIT8; + + _cmsAssert(hIT8 != NULL); + + if (Formatter == NULL) + strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); + else + strncpy(it8->DoubleFormatter, Formatter, sizeof(it8->DoubleFormatter)); + + it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; +} + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmscnvrt.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmscnvrt.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmscnvrt.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmscnvrt.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1243 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin. +// Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric +static +cmsPipeline* DefaultICCintents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +//--------------------------------------------------------------------------------- + +// This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile +// to do the trick (no devicelinks allowed at that position) +static +cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +//--------------------------------------------------------------------------------- + +// This is the entry for black-plane preserving, which are non-ICC. Again, Last profile have to be a output profile +// to do the trick (no devicelinks allowed at that position) +static +cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +//--------------------------------------------------------------------------------- + + +// This is a structure holding implementations for all supported intents. +typedef struct _cms_intents_list { + + cmsUInt32Number Intent; + char Description[256]; + cmsIntentFn Link; + struct _cms_intents_list* Next; + +} cmsIntentsList; + + +// Built-in intents +static cmsIntentsList DefaultIntents[] = { + + { INTENT_PERCEPTUAL, "Perceptual", DefaultICCintents, &DefaultIntents[1] }, + { INTENT_RELATIVE_COLORIMETRIC, "Relative colorimetric", DefaultICCintents, &DefaultIntents[2] }, + { INTENT_SATURATION, "Saturation", DefaultICCintents, &DefaultIntents[3] }, + { INTENT_ABSOLUTE_COLORIMETRIC, "Absolute colorimetric", DefaultICCintents, &DefaultIntents[4] }, + { INTENT_PRESERVE_K_ONLY_PERCEPTUAL, "Perceptual preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[5] }, + { INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC, "Relative colorimetric preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[6] }, + { INTENT_PRESERVE_K_ONLY_SATURATION, "Saturation preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[7] }, + { INTENT_PRESERVE_K_PLANE_PERCEPTUAL, "Perceptual preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[8] }, + { INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC,"Relative colorimetric preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[9] }, + { INTENT_PRESERVE_K_PLANE_SATURATION, "Saturation preserving black plane", BlackPreservingKPlaneIntents, NULL } +}; + + +// A pointer to the beginning of the list +_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL }; + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginIntentsList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsIntentsPluginChunkType newHead = { NULL }; + cmsIntentsList* entry; + cmsIntentsList* Anterior = NULL; + _cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin]; + + // Walk the list copying all nodes + for (entry = head->Intents; + entry != NULL; + entry = entry ->Next) { + + cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Intents == NULL) + newHead.Intents = newEntry; + } + + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType)); +} + +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginIntentsList(ctx, src); + } + else { + static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL }; + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType)); + } +} + + +// Search the list for a suitable intent. Returns NULL if not found +static +cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent) +{ + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); + cmsIntentsList* pt; + + for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next) + if (pt ->Intent == Intent) return pt; + + for (pt = DefaultIntents; pt != NULL; pt = pt -> Next) + if (pt ->Intent == Intent) return pt; + + return NULL; +} + +// Black point compensation. Implemented as a linear scaling in XYZ. Black points +// should come relative to the white point. Fills an matrix/offset element m +// which is organized as a 4x4 matrix. +static +void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, + const cmsCIEXYZ* BlackPointOut, + cmsMAT3* m, cmsVEC3* off) +{ + cmsFloat64Number ax, ay, az, bx, by, bz, tx, ty, tz; + + // Now we need to compute a matrix plus an offset m and of such of + // [m]*bpin + off = bpout + // [m]*D50 + off = D50 + // + // This is a linear scaling in the form ax+b, where + // a = (bpout - D50) / (bpin - D50) + // b = - D50* (bpout - bpin) / (bpin - D50) + + tx = BlackPointIn->X - cmsD50_XYZ()->X; + ty = BlackPointIn->Y - cmsD50_XYZ()->Y; + tz = BlackPointIn->Z - cmsD50_XYZ()->Z; + + ax = (BlackPointOut->X - cmsD50_XYZ()->X) / tx; + ay = (BlackPointOut->Y - cmsD50_XYZ()->Y) / ty; + az = (BlackPointOut->Z - cmsD50_XYZ()->Z) / tz; + + bx = - cmsD50_XYZ()-> X * (BlackPointOut->X - BlackPointIn->X) / tx; + by = - cmsD50_XYZ()-> Y * (BlackPointOut->Y - BlackPointIn->Y) / ty; + bz = - cmsD50_XYZ()-> Z * (BlackPointOut->Z - BlackPointIn->Z) / tz; + + _cmsVEC3init(&m ->v[0], ax, 0, 0); + _cmsVEC3init(&m ->v[1], 0, ay, 0); + _cmsVEC3init(&m ->v[2], 0, 0, az); + _cmsVEC3init(off, bx, by, bz); + +} + + +// Approximate a blackbody illuminant based on CHAD information +static +cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) +{ + // Convert D50 across inverse CHAD to get the absolute white point + cmsVEC3 d, s; + cmsCIEXYZ Dest; + cmsCIExyY DestChromaticity; + cmsFloat64Number TempK; + cmsMAT3 m1, m2; + + m1 = *Chad; + if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; + + s.n[VX] = cmsD50_XYZ() -> X; + s.n[VY] = cmsD50_XYZ() -> Y; + s.n[VZ] = cmsD50_XYZ() -> Z; + + _cmsMAT3eval(&d, &m2, &s); + + Dest.X = d.n[VX]; + Dest.Y = d.n[VY]; + Dest.Z = d.n[VZ]; + + cmsXYZ2xyY(&DestChromaticity, &Dest); + + if (!cmsTempFromWhitePoint(&TempK, &DestChromaticity)) + return -1.0; + + return TempK; +} + +// Compute a CHAD based on a given temperature +static + void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) +{ + cmsCIEXYZ White; + cmsCIExyY ChromaticityOfWhite; + + cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); + cmsxyY2XYZ(&White, &ChromaticityOfWhite); + _cmsAdaptationMatrix(Chad, NULL, &White, cmsD50_XYZ()); +} + +// Join scalings to obtain relative input to absolute and then to relative output. +// Result is stored in a 3x3 matrix +static +cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, + const cmsCIEXYZ* WhitePointIn, + const cmsMAT3* ChromaticAdaptationMatrixIn, + const cmsCIEXYZ* WhitePointOut, + const cmsMAT3* ChromaticAdaptationMatrixOut, + cmsMAT3* m) +{ + cmsMAT3 Scale, m1, m2, m3, m4; + + // TODO: Follow Marc Mahy's recommendation to check if CHAD is same by using M1*M2 == M2*M1. If so, do nothing. + // TODO: Add support for ArgyllArts tag + + // Adaptation state + if (AdaptationState == 1.0) { + + // Observer is fully adapted. Keep chromatic adaptation. + // That is the standard V4 behaviour + _cmsVEC3init(&m->v[0], WhitePointIn->X / WhitePointOut->X, 0, 0); + _cmsVEC3init(&m->v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); + _cmsVEC3init(&m->v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); + + } + else { + + // Incomplete adaptation. This is an advanced feature. + _cmsVEC3init(&Scale.v[0], WhitePointIn->X / WhitePointOut->X, 0, 0); + _cmsVEC3init(&Scale.v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); + _cmsVEC3init(&Scale.v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); + + + if (AdaptationState == 0.0) { + + m1 = *ChromaticAdaptationMatrixOut; + _cmsMAT3per(&m2, &m1, &Scale); + // m2 holds CHAD from output white to D50 times abs. col. scaling + + // Observer is not adapted, undo the chromatic adaptation + _cmsMAT3per(m, &m2, ChromaticAdaptationMatrixOut); + + m3 = *ChromaticAdaptationMatrixIn; + if (!_cmsMAT3inverse(&m3, &m4)) return FALSE; + _cmsMAT3per(m, &m2, &m4); + + } else { + + cmsMAT3 MixedCHAD; + cmsFloat64Number TempSrc, TempDest, Temp; + + m1 = *ChromaticAdaptationMatrixIn; + if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; + _cmsMAT3per(&m3, &m2, &Scale); + // m3 holds CHAD from input white to D50 times abs. col. scaling + + TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); + TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); + + if (TempSrc < 0.0 || TempDest < 0.0) return FALSE; // Something went wrong + + if (_cmsMAT3isIdentity(&Scale) && fabs(TempSrc - TempDest) < 0.01) { + + _cmsMAT3identity(m); + return TRUE; + } + + Temp = (1.0 - AdaptationState) * TempDest + AdaptationState * TempSrc; + + // Get a CHAD from whatever output temperature to D50. This replaces output CHAD + Temp2CHAD(&MixedCHAD, Temp); + + _cmsMAT3per(m, &m3, &MixedCHAD); + } + + } + return TRUE; + +} + +// Just to see if m matrix should be applied +static +cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off) +{ + cmsFloat64Number diff = 0; + cmsMAT3 Ident; + int i; + + if (m == NULL && off == NULL) return TRUE; // NULL is allowed as an empty layer + if (m == NULL && off != NULL) return FALSE; // This is an internal error + + _cmsMAT3identity(&Ident); + + for (i=0; i < 3*3; i++) + diff += fabs(((cmsFloat64Number*)m)[i] - ((cmsFloat64Number*)&Ident)[i]); + + for (i=0; i < 3; i++) + diff += fabs(((cmsFloat64Number*)off)[i]); + + + return (diff < 0.002); +} + + +// Compute the conversion layer +static +cmsBool ComputeConversion(cmsUInt32Number i, + cmsHPROFILE hProfiles[], + cmsUInt32Number Intent, + cmsBool BPC, + cmsFloat64Number AdaptationState, + cmsMAT3* m, cmsVEC3* off) +{ + + int k; + + // m and off are set to identity and this is detected latter on + _cmsMAT3identity(m); + _cmsVEC3init(off, 0, 0, 0); + + // If intent is abs. colorimetric, + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) { + + cmsCIEXYZ WhitePointIn, WhitePointOut; + cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; + + _cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i-1]); + _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]); + + _cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i]); + _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]); + + if (!ComputeAbsoluteIntent(AdaptationState, + &WhitePointIn, &ChromaticAdaptationMatrixIn, + &WhitePointOut, &ChromaticAdaptationMatrixOut, m)) return FALSE; + + } + else { + // Rest of intents may apply BPC. + + if (BPC) { + + cmsCIEXYZ BlackPointIn, BlackPointOut; + + cmsDetectBlackPoint(&BlackPointIn, hProfiles[i-1], Intent, 0); + cmsDetectDestinationBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); + + // If black points are equal, then do nothing + if (BlackPointIn.X != BlackPointOut.X || + BlackPointIn.Y != BlackPointOut.Y || + BlackPointIn.Z != BlackPointOut.Z) + ComputeBlackPointCompensation(&BlackPointIn, &BlackPointOut, m, off); + } + } + + // Offset should be adjusted because the encoding. We encode XYZ normalized to 0..1.0, + // to do that, we divide by MAX_ENCODEABLE_XZY. The conversion stage goes XYZ -> XYZ so + // we have first to convert from encoded to XYZ and then convert back to encoded. + // y = Mx + Off + // x = x'c + // y = M x'c + Off + // y = y'c; y' = y / c + // y' = (Mx'c + Off) /c = Mx' + (Off / c) + + for (k=0; k < 3; k++) { + off ->n[k] /= MAX_ENCODEABLE_XYZ; + } + + return TRUE; +} + + +// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space +static +cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColorSpaceSignature OutPCS, cmsMAT3* m, cmsVEC3* off) +{ + cmsFloat64Number* m_as_dbl = (cmsFloat64Number*) m; + cmsFloat64Number* off_as_dbl = (cmsFloat64Number*) off; + + // Handle PCS mismatches. A specialized stage is added to the LUT in such case + switch (InPCS) { + + case cmsSigXYZData: // Input profile operates in XYZ + + switch (OutPCS) { + + case cmsSigXYZData: // XYZ -> XYZ + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + break; + + case cmsSigLabData: // XYZ -> Lab + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) + return FALSE; + break; + + default: + return FALSE; // Colorspace mismatch + } + break; + + case cmsSigLabData: // Input profile operates in Lab + + switch (OutPCS) { + + case cmsSigXYZData: // Lab -> XYZ + + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID))) + return FALSE; + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + break; + + case cmsSigLabData: // Lab -> Lab + + if (!IsEmptyLayer(m, off)) { + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)) || + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)) || + !cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) + return FALSE; + } + break; + + default: + return FALSE; // Mismatch + } + break; + + // On colorspaces other than PCS, check for same space + default: + if (InPCS != OutPCS) return FALSE; + break; + } + + return TRUE; +} + + +// Is a given space compatible with another? +static +cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature b) +{ + // If they are same, they are compatible. + if (a == b) return TRUE; + + // Check for MCH4 substitution of CMYK + if ((a == cmsSig4colorData) && (b == cmsSigCmykData)) return TRUE; + if ((a == cmsSigCmykData) && (b == cmsSig4colorData)) return TRUE; + + // Check for XYZ/Lab. Those spaces are interchangeable as they can be computed one from other. + if ((a == cmsSigXYZData) && (b == cmsSigLabData)) return TRUE; + if ((a == cmsSigLabData) && (b == cmsSigXYZData)) return TRUE; + + return FALSE; +} + + +// Default handler for ICC-style intents +static +cmsPipeline* DefaultICCintents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsPipeline* Lut = NULL; + cmsPipeline* Result; + cmsHPROFILE hProfile; + cmsMAT3 m; + cmsVEC3 off; + cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut = cmsSigLabData, CurrentColorSpace; + cmsProfileClassSignature ClassSig; + cmsUInt32Number i, Intent; + + // For safety + if (nProfiles == 0) return NULL; + + // Allocate an empty LUT for holding the result. 0 as channel count means 'undefined' + Result = cmsPipelineAlloc(ContextID, 0, 0); + if (Result == NULL) return NULL; + + CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); + + for (i=0; i < nProfiles; i++) { + + cmsBool lIsDeviceLink, lIsInput; + + hProfile = hProfiles[i]; + ClassSig = cmsGetDeviceClass(hProfile); + lIsDeviceLink = (ClassSig == cmsSigLinkClass || ClassSig == cmsSigAbstractClass ); + + // First profile is used as input unless devicelink or abstract + if ((i == 0) && !lIsDeviceLink) { + lIsInput = TRUE; + } + else { + // Else use profile in the input direction if current space is not PCS + lIsInput = (CurrentColorSpace != cmsSigXYZData) && + (CurrentColorSpace != cmsSigLabData); + } + + Intent = TheIntents[i]; + + if (lIsInput || lIsDeviceLink) { + + ColorSpaceIn = cmsGetColorSpace(hProfile); + ColorSpaceOut = cmsGetPCS(hProfile); + } + else { + + ColorSpaceIn = cmsGetPCS(hProfile); + ColorSpaceOut = cmsGetColorSpace(hProfile); + } + + if (!ColorSpaceIsCompatible(ColorSpaceIn, CurrentColorSpace)) { + + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "ColorSpace mismatch"); + goto Error; + } + + // If devicelink is found, then no custom intent is allowed and we can + // read the LUT to be applied. Settings don't apply here. + if (lIsDeviceLink || ((ClassSig == cmsSigNamedColorClass) && (nProfiles == 1))) { + + // Get the involved LUT from the profile + Lut = _cmsReadDevicelinkLUT(hProfile, Intent); + if (Lut == NULL) goto Error; + + // What about abstract profiles? + if (ClassSig == cmsSigAbstractClass && i > 0) { + if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error; + } + else { + _cmsMAT3identity(&m); + _cmsVEC3init(&off, 0, 0, 0); + } + + + if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error; + + } + else { + + if (lIsInput) { + // Input direction means non-pcs connection, so proceed like devicelinks + Lut = _cmsReadInputLUT(hProfile, Intent); + if (Lut == NULL) goto Error; + } + else { + + // Output direction means PCS connection. Intent may apply here + Lut = _cmsReadOutputLUT(hProfile, Intent); + if (Lut == NULL) goto Error; + + + if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error; + if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error; + + } + } + + // Concatenate to the output LUT + if (!cmsPipelineCat(Result, Lut)) + goto Error; + + cmsPipelineFree(Lut); + Lut = NULL; + + // Update current space + CurrentColorSpace = ColorSpaceOut; + } + + // Check for non-negatives clip + if (dwFlags & cmsFLAGS_NONEGATIVES) { + + if (ColorSpaceOut == cmsSigGrayData || + ColorSpaceOut == cmsSigRgbData || + ColorSpaceOut == cmsSigCmykData) { + + cmsStage* clip = _cmsStageClipNegatives(Result->ContextID, cmsChannelsOf(ColorSpaceOut)); + if (clip == NULL) goto Error; + + if (!cmsPipelineInsertStage(Result, cmsAT_END, clip)) + goto Error; + } + + } + + return Result; + +Error: + + if (Lut != NULL) cmsPipelineFree(Lut); + if (Result != NULL) cmsPipelineFree(Result); + return NULL; + + cmsUNUSED_PARAMETER(dwFlags); +} + + +// Wrapper for DLL calling convention +cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + return DefaultICCintents(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags); +} + +// Black preserving intents --------------------------------------------------------------------------------------------- + +// Translate black-preserving intents to ICC ones +static +cmsUInt32Number TranslateNonICCIntents(cmsUInt32Number Intent) +{ + switch (Intent) { + case INTENT_PRESERVE_K_ONLY_PERCEPTUAL: + case INTENT_PRESERVE_K_PLANE_PERCEPTUAL: + return INTENT_PERCEPTUAL; + + case INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC: + case INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC: + return INTENT_RELATIVE_COLORIMETRIC; + + case INTENT_PRESERVE_K_ONLY_SATURATION: + case INTENT_PRESERVE_K_PLANE_SATURATION: + return INTENT_SATURATION; + + default: return Intent; + } +} + +// Sampler for Black-only preserving CMYK->CMYK transforms + +typedef struct { + cmsPipeline* cmyk2cmyk; // The original transform + cmsToneCurve* KTone; // Black-to-black tone curve + +} GrayOnlyParams; + + +// Preserve black only if that is the only ink used +static +int BlackPreservingGrayOnlySampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo) +{ + GrayOnlyParams* bp = (GrayOnlyParams*) Cargo; + + // If going across black only, keep black only + if (In[0] == 0 && In[1] == 0 && In[2] == 0) { + + // TAC does not apply because it is black ink! + Out[0] = Out[1] = Out[2] = 0; + Out[3] = cmsEvalToneCurve16(bp->KTone, In[3]); + return TRUE; + } + + // Keep normal transform for other colors + bp ->cmyk2cmyk ->Eval16Fn(In, Out, bp ->cmyk2cmyk->Data); + return TRUE; +} + +// This is the entry for black-preserving K-only intents, which are non-ICC +static +cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + GrayOnlyParams bp; + cmsPipeline* Result; + cmsUInt32Number ICCIntents[256]; + cmsStage* CLUT; + cmsUInt32Number i, nGridPoints; + cmsUInt32Number lastProfilePos; + cmsUInt32Number preservationProfilesCount; + cmsHPROFILE hLastProfile; + + + // Sanity check + if (nProfiles < 1 || nProfiles > 255) return NULL; + + // Translate black-preserving intents to ICC ones + for (i=0; i < nProfiles; i++) + ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); + + + // Trim all CMYK devicelinks at the end + lastProfilePos = nProfiles - 1; + hLastProfile = hProfiles[lastProfilePos]; + + while (lastProfilePos > 1) + { + hLastProfile = hProfiles[--lastProfilePos]; + if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData || + cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass) + break; + } + + preservationProfilesCount = lastProfilePos + 1; + + // Check for non-cmyk profiles + if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || + !(cmsGetColorSpace(hLastProfile) == cmsSigCmykData || + cmsGetDeviceClass(hLastProfile) == cmsSigOutputClass)) + return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); + + // Allocate an empty LUT for holding the result + Result = cmsPipelineAlloc(ContextID, 4, 4); + if (Result == NULL) return NULL; + + memset(&bp, 0, sizeof(bp)); + + // Create a LUT holding normal ICC transform + bp.cmyk2cmyk = DefaultICCintents(ContextID, + preservationProfilesCount, + ICCIntents, + hProfiles, + BPC, + AdaptationStates, + dwFlags); + + if (bp.cmyk2cmyk == NULL) goto Error; + + // Now, compute the tone curve + bp.KTone = _cmsBuildKToneCurve(ContextID, + 4096, + preservationProfilesCount, + ICCIntents, + hProfiles, + BPC, + AdaptationStates, + dwFlags); + + if (bp.KTone == NULL) goto Error; + + + // How many gridpoints are we going to use? + nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); + + // Create the CLUT. 16 bits + CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); + if (CLUT == NULL) goto Error; + + // This is the one and only MPE in this LUT + if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) + goto Error; + + // Sample it. We cannot afford pre/post linearization this time. + if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) + goto Error; + + + // Insert possible devicelinks at the end + for (i = lastProfilePos + 1; i < nProfiles; i++) + { + cmsPipeline* devlink = _cmsReadDevicelinkLUT(hProfiles[i], ICCIntents[i]); + if (devlink == NULL) + goto Error; + + if (!cmsPipelineCat(Result, devlink)) + goto Error; + } + + + // Get rid of xform and tone curve + cmsPipelineFree(bp.cmyk2cmyk); + cmsFreeToneCurve(bp.KTone); + + return Result; + +Error: + + if (bp.cmyk2cmyk != NULL) cmsPipelineFree(bp.cmyk2cmyk); + if (bp.KTone != NULL) cmsFreeToneCurve(bp.KTone); + if (Result != NULL) cmsPipelineFree(Result); + return NULL; + +} + +// K Plane-preserving CMYK to CMYK ------------------------------------------------------------------------------------ + +typedef struct { + + cmsPipeline* cmyk2cmyk; // The original transform + cmsHTRANSFORM hProofOutput; // Output CMYK to Lab (last profile) + cmsHTRANSFORM cmyk2Lab; // The input chain + cmsToneCurve* KTone; // Black-to-black tone curve + cmsPipeline* LabK2cmyk; // The output profile + cmsFloat64Number MaxError; + + cmsHTRANSFORM hRoundTrip; + cmsFloat64Number MaxTAC; + + +} PreserveKPlaneParams; + + +// The CLUT will be stored at 16 bits, but calculations are performed at cmsFloat32Number precision +static +int BlackPreservingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo) +{ + int i; + cmsFloat32Number Inf[4], Outf[4]; + cmsFloat32Number LabK[4]; + cmsFloat64Number SumCMY, SumCMYK, Error, Ratio; + cmsCIELab ColorimetricLab, BlackPreservingLab; + PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo; + + // Convert from 16 bits to floating point + for (i=0; i < 4; i++) + Inf[i] = (cmsFloat32Number) (In[i] / 65535.0); + + // Get the K across Tone curve + LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]); + + // If going across black only, keep black only + if (In[0] == 0 && In[1] == 0 && In[2] == 0) { + + Out[0] = Out[1] = Out[2] = 0; + Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0); + return TRUE; + } + + // Try the original transform, + cmsPipelineEvalFloat(Inf, Outf, bp ->cmyk2cmyk); + + // Store a copy of the floating point result into 16-bit + for (i=0; i < 4; i++) + Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0); + + // Maybe K is already ok (mostly on K=0) + if (fabsf(Outf[3] - LabK[3]) < (3.0 / 65535.0)) { + return TRUE; + } + + // K differ, measure and keep Lab measurement for further usage + // this is done in relative colorimetric intent + cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1); + + // Is not black only and the transform doesn't keep black. + // Obtain the Lab of output CMYK. After that we have Lab + K + cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1); + + // Obtain the corresponding CMY using reverse interpolation + // (K is fixed in LabK[3]) + if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) { + + // Cannot find a suitable value, so use colorimetric xform + // which is already stored in Out[] + return TRUE; + } + + // Make sure to pass through K (which now is fixed) + Outf[3] = LabK[3]; + + // Apply TAC if needed + SumCMY = (cmsFloat64Number) Outf[0] + Outf[1] + Outf[2]; + SumCMYK = SumCMY + Outf[3]; + + if (SumCMYK > bp ->MaxTAC) { + + Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY); + if (Ratio < 0) + Ratio = 0; + } + else + Ratio = 1.0; + + Out[0] = _cmsQuickSaturateWord(Outf[0] * Ratio * 65535.0); // C + Out[1] = _cmsQuickSaturateWord(Outf[1] * Ratio * 65535.0); // M + Out[2] = _cmsQuickSaturateWord(Outf[2] * Ratio * 65535.0); // Y + Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0); + + // Estimate the error (this goes 16 bits to Lab DBL) + cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); + Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); + if (Error > bp -> MaxError) + bp->MaxError = Error; + + return TRUE; +} + + + +// This is the entry for black-plane preserving, which are non-ICC +static +cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + PreserveKPlaneParams bp; + + cmsPipeline* Result = NULL; + cmsUInt32Number ICCIntents[256]; + cmsStage* CLUT; + cmsUInt32Number i, nGridPoints; + cmsUInt32Number lastProfilePos; + cmsUInt32Number preservationProfilesCount; + cmsHPROFILE hLastProfile; + cmsHPROFILE hLab; + + // Sanity check + if (nProfiles < 1 || nProfiles > 255) return NULL; + + // Translate black-preserving intents to ICC ones + for (i=0; i < nProfiles; i++) + ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); + + // Trim all CMYK devicelinks at the end + lastProfilePos = nProfiles - 1; + hLastProfile = hProfiles[lastProfilePos]; + + while (lastProfilePos > 1) + { + hLastProfile = hProfiles[--lastProfilePos]; + if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData || + cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass) + break; + } + + preservationProfilesCount = lastProfilePos + 1; + + // Check for non-cmyk profiles + if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || + !(cmsGetColorSpace(hLastProfile) == cmsSigCmykData || + cmsGetDeviceClass(hLastProfile) == cmsSigOutputClass)) + return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); + + // Allocate an empty LUT for holding the result + Result = cmsPipelineAlloc(ContextID, 4, 4); + if (Result == NULL) return NULL; + + memset(&bp, 0, sizeof(bp)); + + // We need the input LUT of the last profile, assuming this one is responsible of + // black generation. This LUT will be searched in inverse order. + bp.LabK2cmyk = _cmsReadInputLUT(hLastProfile, INTENT_RELATIVE_COLORIMETRIC); + if (bp.LabK2cmyk == NULL) goto Cleanup; + + // Get total area coverage (in 0..1 domain) + bp.MaxTAC = cmsDetectTAC(hLastProfile) / 100.0; + if (bp.MaxTAC <= 0) goto Cleanup; + + + // Create a LUT holding normal ICC transform + bp.cmyk2cmyk = DefaultICCintents(ContextID, + preservationProfilesCount, + ICCIntents, + hProfiles, + BPC, + AdaptationStates, + dwFlags); + if (bp.cmyk2cmyk == NULL) goto Cleanup; + + // Now the tone curve + bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, preservationProfilesCount, + ICCIntents, + hProfiles, + BPC, + AdaptationStates, + dwFlags); + if (bp.KTone == NULL) goto Cleanup; + + // To measure the output, Last profile to Lab + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + bp.hProofOutput = cmsCreateTransformTHR(ContextID, hLastProfile, + CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + if ( bp.hProofOutput == NULL) goto Cleanup; + + // Same as anterior, but lab in the 0..1 range + bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hLastProfile, + FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab, + FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4), + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + if (bp.cmyk2Lab == NULL) goto Cleanup; + cmsCloseProfile(hLab); + + // Error estimation (for debug only) + bp.MaxError = 0; + + // How many gridpoints are we going to use? + nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); + + + CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); + if (CLUT == NULL) goto Cleanup; + + if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) + goto Cleanup; + + cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0); + + // Insert possible devicelinks at the end + for (i = lastProfilePos + 1; i < nProfiles; i++) + { + cmsPipeline* devlink = _cmsReadDevicelinkLUT(hProfiles[i], ICCIntents[i]); + if (devlink == NULL) + goto Cleanup; + + if (!cmsPipelineCat(Result, devlink)) + goto Cleanup; + } + + +Cleanup: + + if (bp.cmyk2cmyk) cmsPipelineFree(bp.cmyk2cmyk); + if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab); + if (bp.hProofOutput) cmsDeleteTransform(bp.hProofOutput); + + if (bp.KTone) cmsFreeToneCurve(bp.KTone); + if (bp.LabK2cmyk) cmsPipelineFree(bp.LabK2cmyk); + + return Result; +} + + + +// Link routines ------------------------------------------------------------------------------------------------------ + +// Chain several profiles into a single LUT. It just checks the parameters and then calls the handler +// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the +// rest of intents in chain. A maximum of 255 profiles at time are supported, which is pretty reasonable. +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsUInt32Number i; + cmsIntentsList* Intent; + + // Make sure a reasonable number of profiles is provided + if (nProfiles <= 0 || nProfiles > 255) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't link '%d' profiles", nProfiles); + return NULL; + } + + for (i=0; i < nProfiles; i++) { + + // Check if black point is really needed or allowed. Note that + // following Adobe's document: + // BPC does not apply to devicelink profiles, nor to abs colorimetric, + // and applies always on V4 perceptual and saturation. + + if (TheIntents[i] == INTENT_ABSOLUTE_COLORIMETRIC) + BPC[i] = FALSE; + + if (TheIntents[i] == INTENT_PERCEPTUAL || TheIntents[i] == INTENT_SATURATION) { + + // Force BPC for V4 profiles in perceptual and saturation + if (cmsGetEncodedICCversion(hProfiles[i]) >= 0x4000000) + BPC[i] = TRUE; + } + } + + // Search for a handler. The first intent in the chain defines the handler. That would + // prevent using multiple custom intents in a multiintent chain, but the behaviour of + // this case would present some issues if the custom intent tries to do things like + // preserve primaries. This solution is not perfect, but works well on most cases. + + Intent = SearchIntent(ContextID, TheIntents[0]); + if (Intent == NULL) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); + return NULL; + } + + // Call the handler + return Intent ->Link(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags); +} + +// ------------------------------------------------------------------------------------------------- + +// Get information about available intents. nMax is the maximum space for the supplied "Codes" +// and "Descriptions" the function returns the total number of intents, which may be greater +// than nMax, although the matrices are not populated beyond this level. +cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +{ + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); + cmsIntentsList* pt; + cmsUInt32Number nIntents; + + + for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) + { + if (nIntents < nMax) { + if (Codes != NULL) + Codes[nIntents] = pt ->Intent; + + if (Descriptions != NULL) + Descriptions[nIntents] = pt ->Description; + } + + nIntents++; + } + + for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) + { + if (nIntents < nMax) { + if (Codes != NULL) + Codes[nIntents] = pt ->Intent; + + if (Descriptions != NULL) + Descriptions[nIntents] = pt ->Description; + } + + nIntents++; + } + return nIntents; +} + +cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +{ + return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions); +} + +// The plug-in registration. User can add new intents or override default routines +cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) +{ + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin); + cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; + cmsIntentsList* fl; + + // Do we have to reset the custom intents? + if (Data == NULL) { + + ctx->Intents = NULL; + return TRUE; + } + + fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); + if (fl == NULL) return FALSE; + + + fl ->Intent = Plugin ->Intent; + strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1); + fl ->Description[sizeof(fl ->Description)-1] = 0; + + fl ->Link = Plugin ->Link; + + fl ->Next = ctx ->Intents; + ctx ->Intents = fl; + + return TRUE; +} + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmserr.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmserr.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmserr.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmserr.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,692 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- + +#include "lcms2_internal.h" + + +// This function is here to help applications to prevent mixing lcms versions on header and shared objects. +int CMSEXPORT cmsGetEncodedCMMversion(void) +{ + return LCMS_VERSION; +} + +// I am so tired about incompatibilities on those functions that here are some replacements +// that hopefully would be fully portable. + +// compare two strings ignoring case +int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) +{ + CMSREGISTER const unsigned char *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + while (toupper(*us1) == toupper(*us2++)) + if (*us1++ == '\0') + return 0; + + return (toupper(*us1) - toupper(*--us2)); +} + +// long int because C99 specifies ftell in such way (7.19.9.2) +long int CMSEXPORT cmsfilelength(FILE* f) +{ + long int p , n; + + p = ftell(f); // register current file position + if (p == -1L) + return -1L; + + if (fseek(f, 0, SEEK_END) != 0) { + return -1L; + } + + n = ftell(f); + fseek(f, p, SEEK_SET); // file position restored + + return n; +} + + +// Memory handling ------------------------------------------------------------------ +// +// This is the interface to low-level memory management routines. By default a simple +// wrapping to malloc/free/realloc is provided, although there is a limit on the max +// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent +// bogus or evil code to allocate huge blocks that otherwise lcms would never need. + +#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) + +// User may override this behaviour by using a memory plug-in, which basically replaces +// the default memory management functions. In this case, no check is performed and it +// is up to the plug-in writter to keep in the safe side. There are only three functions +// required to be implemented: malloc, realloc and free, although the user may want to +// replace the optional mallocZero, calloc and dup as well. + +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// ********************************************************************************* + +// This is the default memory allocation function. It does a very coarse +// check of amount of memory, just to prevent exploits +static +void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) +{ + if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum + + return (void*) malloc(size); + + cmsUNUSED_PARAMETER(ContextID); +} + +// Generic allocate & zero +static +void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size) +{ + void *pt = _cmsMalloc(ContextID, size); + if (pt == NULL) return NULL; + + memset(pt, 0, size); + return pt; +} + + +// The default free function. The only check proformed is against NULL pointers +static +void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) +{ + // free(NULL) is defined a no-op by C99, therefore it is safe to + // avoid the check, but it is here just in case... + + if (Ptr) free(Ptr); + + cmsUNUSED_PARAMETER(ContextID); +} + +// The default realloc function. Again it checks for exploits. If Ptr is NULL, +// realloc behaves the same way as malloc and allocates a new block of size bytes. +static +void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) +{ + + if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb + + return realloc(Ptr, size); + + cmsUNUSED_PARAMETER(ContextID); +} + + +// The default calloc function. Allocates an array of num elements, each one of size bytes +// all memory is initialized to zero. +static +void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) +{ + cmsUInt32Number Total = num * size; + + // Preserve calloc behaviour + if (Total == 0) return NULL; + + // Safe check for overflow. + if (num >= UINT_MAX / size) return NULL; + + // Check for overflow + if (Total < num || Total < size) { + return NULL; + } + + if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb + + return _cmsMallocZero(ContextID, Total); +} + +// Generic block duplication +static +void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size) +{ + void* mem; + + if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb + + mem = _cmsMalloc(ContextID, size); + + if (mem != NULL && Org != NULL) + memmove(mem, Org, size); + + return mem; +} + + +// Pointers to memory manager functions in Context0 +_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, + _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn + }; + + +// Reset and duplicate memory manager +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate + ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); + } + else { + + // To reset it, we use the default allocators, which cannot be overridden + ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; + } +} + +// Auxiliary to fill memory management functions from plugin (or context 0 defaults) +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) +{ + if (Plugin == NULL) { + + memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); + } + else { + + ptr ->MallocPtr = Plugin -> MallocPtr; + ptr ->FreePtr = Plugin -> FreePtr; + ptr ->ReallocPtr = Plugin -> ReallocPtr; + + // Make sure we revert to defaults + ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; + ptr ->CallocPtr = _cmsCallocDefaultFn; + ptr ->DupPtr = _cmsDupDefaultFn; + + if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; + if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; + if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; + + } +} + + +// Plug-in replacement entry +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) +{ + cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; + _cmsMemPluginChunkType* ptr; + + // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. + // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the + // context internal data should be malloce'd by using those functions. + if (Data == NULL) { + + struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; + + // Return to the default allocators + if (ContextID != NULL) { + ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; + } + return TRUE; + } + + // Check for required callbacks + if (Plugin -> MallocPtr == NULL || + Plugin -> FreePtr == NULL || + Plugin -> ReallocPtr == NULL) return FALSE; + + // Set replacement functions + ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + if (ptr == NULL) + return FALSE; + + _cmsInstallAllocFunctions(Plugin, ptr); + return TRUE; +} + +// Generic allocate +void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) +{ + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->MallocPtr(ContextID, size); +} + +// Generic allocate & zero +void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) +{ + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->MallocZeroPtr(ContextID, size); +} + +// Generic calloc +void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) +{ + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->CallocPtr(ContextID, num, size); +} + +// Generic reallocate +void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) +{ + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->ReallocPtr(ContextID, Ptr, size); +} + +// Generic free memory +void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) +{ + if (Ptr != NULL) { + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + ptr ->FreePtr(ContextID, Ptr); + } +} + +// Generic block duplication +void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) +{ + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->DupPtr(ContextID, Org, size); +} + +// ******************************************************************************************** + +// Sub allocation takes care of many pointers of small size. The memory allocated in +// this way have be freed at once. Next function allocates a single chunk for linked list +// I prefer this method over realloc due to the big inpact on xput realloc may have if +// memory is being swapped to disk. This approach is safer (although that may not be true on all platforms) +static +_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial) +{ + _cmsSubAllocator_chunk* chunk; + + // 20K by default + if (Initial == 0) + Initial = 20*1024; + + // Create the container + chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk)); + if (chunk == NULL) return NULL; + + // Initialize values + chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial); + if (chunk ->Block == NULL) { + + // Something went wrong + _cmsFree(ContextID, chunk); + return NULL; + } + + chunk ->BlockSize = Initial; + chunk ->Used = 0; + chunk ->next = NULL; + + return chunk; +} + +// The suballocated is nothing but a pointer to the first element in the list. We also keep +// the thread ID in this structure. +_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial) +{ + _cmsSubAllocator* sub; + + // Create the container + sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator)); + if (sub == NULL) return NULL; + + sub ->ContextID = ContextID; + + sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial); + if (sub ->h == NULL) { + _cmsFree(ContextID, sub); + return NULL; + } + + return sub; +} + + +// Get rid of whole linked list +void _cmsSubAllocDestroy(_cmsSubAllocator* sub) +{ + _cmsSubAllocator_chunk *chunk, *n; + + for (chunk = sub ->h; chunk != NULL; chunk = n) { + + n = chunk->next; + if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block); + _cmsFree(sub ->ContextID, chunk); + } + + // Free the header + _cmsFree(sub ->ContextID, sub); +} + + +// Get a pointer to small memory block. +void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) +{ + cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used; + cmsUInt8Number* ptr; + + size = _cmsALIGNMEM(size); + + // Check for memory. If there is no room, allocate a new chunk of double memory size. + if (size > Free) { + + _cmsSubAllocator_chunk* chunk; + cmsUInt32Number newSize; + + newSize = sub -> h ->BlockSize * 2; + if (newSize < size) newSize = size; + + chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize); + if (chunk == NULL) return NULL; + + // Link list + chunk ->next = sub ->h; + sub ->h = chunk; + + } + + ptr = sub -> h ->Block + sub -> h ->Used; + sub -> h -> Used += size; + + return (void*) ptr; +} + +// Duplicate in pool +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) +{ + void *NewPtr; + + // Dup of null pointer is also NULL + if (ptr == NULL) + return NULL; + + NewPtr = _cmsSubAlloc(s, size); + + if (ptr != NULL && NewPtr != NULL) { + memcpy(NewPtr, ptr, size); + } + + return NewPtr; +} + + + +// Error logging ****************************************************************** + +// There is no error handling at all. When a function fails, it returns proper value. +// For example, all create functions does return NULL on failure. Other return FALSE +// It may be interesting, for the developer, to know why the function is failing. +// for that reason, lcms2 does offer a logging function. This function does receive +// a ENGLISH string with some clues on what is going wrong. You can show this +// info to the end user, or just create some sort of log. +// The logging function should NOT terminate the program, as this obviously can leave +// resources. It is the programmer's responsibility to check each function return code +// to make sure it didn't fail. + +// Error messages are limited to MAX_ERROR_MESSAGE_LEN + +#define MAX_ERROR_MESSAGE_LEN 1024 + +// --------------------------------------------------------------------------------------------------------- + +// This is our default log error +static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); + +// Context0 storage, which is global +_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction }; + +// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value +// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; + void* from; + + if (src != NULL) { + from = src ->chunks[Logger]; + } + else { + from = &LogErrorChunk; + } + + ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); +} + +// The default error logger does nothing. +static +void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text) +{ + // fprintf(stderr, "[lcms]: %s\n", Text); + // fflush(stderr); + + cmsUNUSED_PARAMETER(ContextID); + cmsUNUSED_PARAMETER(ErrorCode); + cmsUNUSED_PARAMETER(Text); +} + +// Change log error, context based +void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) +{ + _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + + if (lhg != NULL) { + + if (Fn == NULL) + lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; + else + lhg -> LogErrorHandler = Fn; + } +} + +// Change log error, legacy +void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) +{ + cmsSetLogErrorHandlerTHR(NULL, Fn); +} + +// Log an error +// ErrorText is a text holding an english description of error. +void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...) +{ + va_list args; + char Buffer[MAX_ERROR_MESSAGE_LEN]; + _cmsLogErrorChunkType* lhg; + + + va_start(args, ErrorText); + vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); + va_end(args); + + // Check for the context, if specified go there. If not, go for the global + lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + if (lhg ->LogErrorHandler) { + lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); + } +} + +// Utility function to print signatures +void _cmsTagSignature2String(char String[5], cmsTagSignature sig) +{ + cmsUInt32Number be; + + // Convert to big endian + be = _cmsAdjustEndianess32((cmsUInt32Number) sig); + + // Move chars + memmove(String, &be, 4); + + // Make sure of terminator + String[4] = 0; +} + +//-------------------------------------------------------------------------------------------------- + + +static +void* defMtxCreate(cmsContext id) +{ + _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex)); + _cmsInitMutexPrimitive(ptr_mutex); + return (void*) ptr_mutex; +} + +static +void defMtxDestroy(cmsContext id, void* mtx) +{ + _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); + _cmsFree(id, mtx); +} + +static +cmsBool defMtxLock(cmsContext id, void* mtx) +{ + cmsUNUSED_PARAMETER(id); + return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; +} + +static +void defMtxUnlock(cmsContext id, void* mtx) +{ + cmsUNUSED_PARAMETER(id); + _cmsUnlockPrimitive((_cmsMutex *) mtx); +} + + + +// Pointers to memory manager functions in Context0 +_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; + void* from; + + if (src != NULL) { + from = src ->chunks[MutexPlugin]; + } + else { + from = &MutexChunk; + } + + ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); +} + +// Register new ways to transform +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; + _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (Data == NULL) { + + // No lock routines + ctx->CreateMutexPtr = NULL; + ctx->DestroyMutexPtr = NULL; + ctx->LockMutexPtr = NULL; + ctx ->UnlockMutexPtr = NULL; + return TRUE; + } + + // Factory callback is required + if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || + Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; + + + ctx->CreateMutexPtr = Plugin->CreateMutexPtr; + ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; + ctx ->LockMutexPtr = Plugin ->LockMutexPtr; + ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; + + // All is ok + return TRUE; +} + +// Generic Mutex fns +void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->CreateMutexPtr == NULL) return NULL; + + return ptr ->CreateMutexPtr(ContextID); +} + +void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->DestroyMutexPtr != NULL) { + + ptr ->DestroyMutexPtr(ContextID, mtx); + } +} + +cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->LockMutexPtr == NULL) return TRUE; + + return ptr ->LockMutexPtr(ContextID, mtx); +} + +void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->UnlockMutexPtr != NULL) { + + ptr ->UnlockMutexPtr(ContextID, mtx); + } +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsgamma.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsgamma.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsgamma.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsgamma.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1517 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// +#include "lcms2_internal.h" + +// Tone curves are powerful constructs that can contain curves specified in diverse ways. +// The curve is stored in segments, where each segment can be sampled or specified by parameters. +// a 16.bit simplification of the *whole* curve is kept for optimization purposes. For float operation, +// each segment is evaluated separately. Plug-ins may be used to define new parametric schemes, +// each plug-in may define up to MAX_TYPES_IN_LCMS_PLUGIN functions types. For defining a function, +// the plug-in should provide the type id, how many parameters each type has, and a pointer to +// a procedure that evaluates the function. In the case of reverse evaluation, the evaluator will +// be called with the type id as a negative value, and a sampled version of the reversed curve +// will be built. + +// ----------------------------------------------------------------- Implementation +// Maxim number of nodes +#define MAX_NODES_IN_CURVE 4097 +#define MINUS_INF (-1E22F) +#define PLUS_INF (+1E22F) + +// The list of supported parametric curves +typedef struct _cmsParametricCurvesCollection_st { + + cmsUInt32Number nFunctions; // Number of supported functions in this chunk + cmsInt32Number FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types + cmsUInt32Number ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function + + cmsParametricCurveEvaluator Evaluator; // The evaluator + + struct _cmsParametricCurvesCollection_st* Next; // Next in list + +} _cmsParametricCurvesCollection; + +// This is the default (built-in) evaluator +static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R); + +// The built-in list +static _cmsParametricCurvesCollection DefaultCurves = { + 10, // # of curve types + { 1, 2, 3, 4, 5, 6, 7, 8, 108, 109 }, // Parametric curve ID + { 1, 3, 4, 5, 7, 4, 5, 5, 1, 1 }, // Parameters by type + DefaultEvalParametricFn, // Evaluator + NULL // Next in chain +}; + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginCurvesList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsCurvesPluginChunkType newHead = { NULL }; + _cmsParametricCurvesCollection* entry; + _cmsParametricCurvesCollection* Anterior = NULL; + _cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->ParametricCurves; + entry != NULL; + entry = entry ->Next) { + + _cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.ParametricCurves == NULL) + newHead.ParametricCurves = newEntry; + } + + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType)); +} + +// The allocator have to follow the chain +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Copy all linked list + DupPluginCurvesList(ctx, src); + } + else { + static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL }; + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType)); + } +} + + +// The linked list head +_cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL }; + +// As a way to install new parametric curves +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); + cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; + _cmsParametricCurvesCollection* fl; + + if (Data == NULL) { + + ctx -> ParametricCurves = NULL; + return TRUE; + } + + fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection)); + if (fl == NULL) return FALSE; + + // Copy the parameters + fl ->Evaluator = Plugin ->Evaluator; + fl ->nFunctions = Plugin ->nFunctions; + + // Make sure no mem overwrites + if (fl ->nFunctions > MAX_TYPES_IN_LCMS_PLUGIN) + fl ->nFunctions = MAX_TYPES_IN_LCMS_PLUGIN; + + // Copy the data + memmove(fl->FunctionTypes, Plugin ->FunctionTypes, fl->nFunctions * sizeof(cmsUInt32Number)); + memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number)); + + // Keep linked list + fl ->Next = ctx->ParametricCurves; + ctx->ParametricCurves = fl; + + // All is ok + return TRUE; +} + + +// Search in type list, return position or -1 if not found +static +int IsInSet(int Type, _cmsParametricCurvesCollection* c) +{ + int i; + + for (i=0; i < (int) c ->nFunctions; i++) + if (abs(Type) == c ->FunctionTypes[i]) return i; + + return -1; +} + + +// Search for the collection which contains a specific type +static +_cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index) +{ + _cmsParametricCurvesCollection* c; + int Position; + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); + + for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) { + + Position = IsInSet(Type, c); + + if (Position != -1) { + if (index != NULL) + *index = Position; + return c; + } + } + // If none found, revert for defaults + for (c = &DefaultCurves; c != NULL; c = c ->Next) { + + Position = IsInSet(Type, c); + + if (Position != -1) { + if (index != NULL) + *index = Position; + return c; + } + } + + return NULL; +} + +// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case +// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the +// optimization curve is given. Both features simultaneously is an error +static +cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries, + cmsUInt32Number nSegments, const cmsCurveSegment* Segments, + const cmsUInt16Number* Values) +{ + cmsToneCurve* p; + cmsUInt32Number i; + + // We allow huge tables, which are then restricted for smoothing operations + if (nEntries > 65530) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve of more than 65530 entries"); + return NULL; + } + + if (nEntries == 0 && nSegments == 0) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve with zero segments and no table"); + return NULL; + } + + // Allocate all required pointers, etc. + p = (cmsToneCurve*) _cmsMallocZero(ContextID, sizeof(cmsToneCurve)); + if (!p) return NULL; + + // In this case, there are no segments + if (nSegments == 0) { + p ->Segments = NULL; + p ->Evals = NULL; + } + else { + p ->Segments = (cmsCurveSegment*) _cmsCalloc(ContextID, nSegments, sizeof(cmsCurveSegment)); + if (p ->Segments == NULL) goto Error; + + p ->Evals = (cmsParametricCurveEvaluator*) _cmsCalloc(ContextID, nSegments, sizeof(cmsParametricCurveEvaluator)); + if (p ->Evals == NULL) goto Error; + } + + p -> nSegments = nSegments; + + // This 16-bit table contains a limited precision representation of the whole curve and is kept for + // increasing xput on certain operations. + if (nEntries == 0) { + p ->Table16 = NULL; + } + else { + p ->Table16 = (cmsUInt16Number*) _cmsCalloc(ContextID, nEntries, sizeof(cmsUInt16Number)); + if (p ->Table16 == NULL) goto Error; + } + + p -> nEntries = nEntries; + + // Initialize members if requested + if (Values != NULL && (nEntries > 0)) { + + for (i=0; i < nEntries; i++) + p ->Table16[i] = Values[i]; + } + + // Initialize the segments stuff. The evaluator for each segment is located and a pointer to it + // is placed in advance to maximize performance. + if (Segments != NULL && (nSegments > 0)) { + + _cmsParametricCurvesCollection *c; + + p ->SegInterp = (cmsInterpParams**) _cmsCalloc(ContextID, nSegments, sizeof(cmsInterpParams*)); + if (p ->SegInterp == NULL) goto Error; + + for (i=0; i < nSegments; i++) { + + // Type 0 is a special marker for table-based curves + if (Segments[i].Type == 0) + p ->SegInterp[i] = _cmsComputeInterpParams(ContextID, Segments[i].nGridPoints, 1, 1, NULL, CMS_LERP_FLAGS_FLOAT); + + memmove(&p ->Segments[i], &Segments[i], sizeof(cmsCurveSegment)); + + if (Segments[i].Type == 0 && Segments[i].SampledPoints != NULL) + p ->Segments[i].SampledPoints = (cmsFloat32Number*) _cmsDupMem(ContextID, Segments[i].SampledPoints, sizeof(cmsFloat32Number) * Segments[i].nGridPoints); + else + p ->Segments[i].SampledPoints = NULL; + + + c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL); + if (c != NULL) + p ->Evals[i] = c ->Evaluator; + } + } + + p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS); + if (p->InterpParams != NULL) + return p; + +Error: + if (p -> SegInterp) _cmsFree(ContextID, p -> SegInterp); + if (p -> Segments) _cmsFree(ContextID, p -> Segments); + if (p -> Evals) _cmsFree(ContextID, p -> Evals); + if (p ->Table16) _cmsFree(ContextID, p ->Table16); + _cmsFree(ContextID, p); + return NULL; +} + + +// Generates a sigmoidal function with desired steepness. +cmsINLINE double sigmoid_base(double k, double t) +{ + return (1.0 / (1.0 + exp(-k * t))) - 0.5; +} + +cmsINLINE double inverted_sigmoid_base(double k, double t) +{ + return -log((1.0 / (t + 0.5)) - 1.0) / k; +} + +cmsINLINE double sigmoid_factory(double k, double t) +{ + double correction = 0.5 / sigmoid_base(k, 1); + + return correction * sigmoid_base(k, 2.0 * t - 1.0) + 0.5; +} + +cmsINLINE double inverse_sigmoid_factory(double k, double t) +{ + double correction = 0.5 / sigmoid_base(k, 1); + + return (inverted_sigmoid_base(k, (t - 0.5) / correction) + 1.0) / 2.0; +} + + +// Parametric Fn using floating point +static +cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R) +{ + cmsFloat64Number e, Val, disc; + + switch (Type) { + + // X = Y ^ Gamma + case 1: + if (R < 0) { + + if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE) + Val = R; + else + Val = 0; + } + else + Val = pow(R, Params[0]); + break; + + // Type 1 Reversed: X = Y ^1/gamma + case -1: + if (R < 0) { + + if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE) + Val = R; + else + Val = 0; + } + else + { + if (fabs(Params[0]) < MATRIX_DET_TOLERANCE) + Val = PLUS_INF; + else + Val = pow(R, 1 / Params[0]); + } + break; + + // CIE 122-1966 + // Y = (aX + b)^Gamma | X >= -b/a + // Y = 0 | else + case 2: + { + + if (fabs(Params[1]) < MATRIX_DET_TOLERANCE) + { + Val = 0; + } + else + { + disc = -Params[2] / Params[1]; + + if (R >= disc) { + + e = Params[1] * R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]); + else + Val = 0; + } + else + Val = 0; + } + } + break; + + // Type 2 Reversed + // X = (Y ^1/g - b) / a + case -2: + { + if (fabs(Params[0]) < MATRIX_DET_TOLERANCE || + fabs(Params[1]) < MATRIX_DET_TOLERANCE) + { + Val = 0; + } + else + { + if (R < 0) + Val = 0; + else + Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1]; + + if (Val < 0) + Val = 0; + } + } + break; + + + // IEC 61966-3 + // Y = (aX + b)^Gamma | X <= -b/a + // Y = c | else + case 3: + { + if (fabs(Params[1]) < MATRIX_DET_TOLERANCE) + { + Val = 0; + } + else + { + disc = -Params[2] / Params[1]; + if (disc < 0) + disc = 0; + + if (R >= disc) { + + e = Params[1] * R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]) + Params[3]; + else + Val = 0; + } + else + Val = Params[3]; + } + } + break; + + + // Type 3 reversed + // X=((Y-c)^1/g - b)/a | (Y>=c) + // X=-b/a | (Y= Params[3]) { + + e = R - Params[3]; + + if (e > 0) + Val = (pow(e, 1 / Params[0]) - Params[2]) / Params[1]; + else + Val = 0; + } + else { + Val = -Params[2] / Params[1]; + } + } + } + break; + + + // IEC 61966-2.1 (sRGB) + // Y = (aX + b)^Gamma | X >= d + // Y = cX | X < d + case 4: + if (R >= Params[4]) { + + e = Params[1]*R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]); + else + Val = 0; + } + else + Val = R * Params[3]; + break; + + // Type 4 reversed + // X=((Y^1/g-b)/a) | Y >= (ad+b)^g + // X=Y/c | Y< (ad+b)^g + case -4: + { + if (fabs(Params[0]) < MATRIX_DET_TOLERANCE || + fabs(Params[1]) < MATRIX_DET_TOLERANCE || + fabs(Params[3]) < MATRIX_DET_TOLERANCE) + { + Val = 0; + } + else + { + e = Params[1] * Params[4] + Params[2]; + if (e < 0) + disc = 0; + else + disc = pow(e, Params[0]); + + if (R >= disc) { + + Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1]; + } + else { + Val = R / Params[3]; + } + } + } + break; + + + // Y = (aX + b)^Gamma + e | X >= d + // Y = cX + f | X < d + case 5: + if (R >= Params[4]) { + + e = Params[1]*R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]) + Params[5]; + else + Val = Params[5]; + } + else + Val = R*Params[3] + Params[6]; + break; + + + // Reversed type 5 + // X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e), cd+f + // X=(Y-f)/c | else + case -5: + { + if (fabs(Params[1]) < MATRIX_DET_TOLERANCE || + fabs(Params[3]) < MATRIX_DET_TOLERANCE) + { + Val = 0; + } + else + { + disc = Params[3] * Params[4] + Params[6]; + if (R >= disc) { + + e = R - Params[5]; + if (e < 0) + Val = 0; + else + Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1]; + } + else { + Val = (R - Params[6]) / Params[3]; + } + } + } + break; + + + // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf + // Type 6 is basically identical to type 5 without d + + // Y = (a * X + b) ^ Gamma + c + case 6: + e = Params[1]*R + Params[2]; + + if (e < 0) + Val = Params[3]; + else + Val = pow(e, Params[0]) + Params[3]; + break; + + // ((Y - c) ^1/Gamma - b) / a + case -6: + { + if (fabs(Params[1]) < MATRIX_DET_TOLERANCE) + { + Val = 0; + } + else + { + e = R - Params[3]; + if (e < 0) + Val = 0; + else + Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1]; + } + } + break; + + + // Y = a * log (b * X^Gamma + c) + d + case 7: + + e = Params[2] * pow(R, Params[0]) + Params[3]; + if (e <= 0) + Val = Params[4]; + else + Val = Params[1]*log10(e) + Params[4]; + break; + + // (Y - d) / a = log(b * X ^Gamma + c) + // pow(10, (Y-d) / a) = b * X ^Gamma + c + // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X + case -7: + { + if (fabs(Params[0]) < MATRIX_DET_TOLERANCE || + fabs(Params[1]) < MATRIX_DET_TOLERANCE || + fabs(Params[2]) < MATRIX_DET_TOLERANCE) + { + Val = 0; + } + else + { + Val = pow((pow(10.0, (R - Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]); + } + } + break; + + + //Y = a * b^(c*X+d) + e + case 8: + Val = (Params[0] * pow(Params[1], Params[2] * R + Params[3]) + Params[4]); + break; + + + // Y = (log((y-e) / a) / log(b) - d ) / c + // a=0, b=1, c=2, d=3, e=4, + case -8: + + disc = R - Params[4]; + if (disc < 0) Val = 0; + else + { + if (fabs(Params[0]) < MATRIX_DET_TOLERANCE || + fabs(Params[2]) < MATRIX_DET_TOLERANCE) + { + Val = 0; + } + else + { + Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2]; + } + } + break; + + + // S-Shaped: (1 - (1-x)^1/g)^1/g + case 108: + if (fabs(Params[0]) < MATRIX_DET_TOLERANCE) + Val = 0; + else + Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]); + break; + + // y = (1 - (1-x)^1/g)^1/g + // y^g = (1 - (1-x)^1/g) + // 1 - y^g = (1-x)^1/g + // (1 - y^g)^g = 1 - x + // 1 - (1 - y^g)^g + case -108: + Val = 1 - pow(1 - pow(R, Params[0]), Params[0]); + break; + + // Sigmoidals + case 109: + Val = sigmoid_factory(Params[0], R); + break; + + case -109: + Val = inverse_sigmoid_factory(Params[0], R); + break; + + default: + // Unsupported parametric curve. Should never reach here + return 0; + } + + return Val; +} + +// Evaluate a segmented function for a single value. Return -Inf if no valid segment found . +// If fn type is 0, perform an interpolation on the table +static +cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) +{ + int i; + cmsFloat32Number Out32; + cmsFloat64Number Out; + + for (i = (int) g->nSegments - 1; i >= 0; --i) { + + // Check for domain + if ((R > g->Segments[i].x0) && (R <= g->Segments[i].x1)) { + + // Type == 0 means segment is sampled + if (g->Segments[i].Type == 0) { + + cmsFloat32Number R1 = (cmsFloat32Number)(R - g->Segments[i].x0) / (g->Segments[i].x1 - g->Segments[i].x0); + + // Setup the table (TODO: clean that) + g->SegInterp[i]->Table = g->Segments[i].SampledPoints; + + g->SegInterp[i]->Interpolation.LerpFloat(&R1, &Out32, g->SegInterp[i]); + Out = (cmsFloat64Number) Out32; + + } + else { + Out = g->Evals[i](g->Segments[i].Type, g->Segments[i].Params, R); + } + + if (isinf(Out)) + return PLUS_INF; + else + { + if (isinf(-Out)) + return MINUS_INF; + } + + return Out; + } + } + + return MINUS_INF; +} + +// Access to estimated low-res table +cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + return t ->nEntries; +} + +const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + return t ->Table16; +} + + +// Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the +// floating point description empty. +cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsUInt32Number nEntries, const cmsUInt16Number Values[]) +{ + return AllocateToneCurveStruct(ContextID, nEntries, 0, NULL, Values); +} + +static +cmsUInt32Number EntriesByGamma(cmsFloat64Number Gamma) +{ + if (fabs(Gamma - 1.0) < 0.001) return 2; + return 4096; +} + + +// Create a segmented gamma, fill the table +cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, + cmsUInt32Number nSegments, const cmsCurveSegment Segments[]) +{ + cmsUInt32Number i; + cmsFloat64Number R, Val; + cmsToneCurve* g; + cmsUInt32Number nGridPoints = 4096; + + _cmsAssert(Segments != NULL); + + // Optimizatin for identity curves. + if (nSegments == 1 && Segments[0].Type == 1) { + + nGridPoints = EntriesByGamma(Segments[0].Params[0]); + } + + g = AllocateToneCurveStruct(ContextID, nGridPoints, nSegments, Segments, NULL); + if (g == NULL) return NULL; + + // Once we have the floating point version, we can approximate a 16 bit table of 4096 entries + // for performance reasons. This table would normally not be used except on 8/16 bits transforms. + for (i = 0; i < nGridPoints; i++) { + + R = (cmsFloat64Number) i / (nGridPoints-1); + + Val = EvalSegmentedFn(g, R); + + // Round and saturate + g ->Table16[i] = _cmsQuickSaturateWord(Val * 65535.0); + } + + return g; +} + +// Use a segmented curve to store the floating point table +cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]) +{ + cmsCurveSegment Seg[3]; + + // A segmented tone curve should have function segments in the first and last positions + // Initialize segmented curve part up to 0 to constant value = samples[0] + Seg[0].x0 = MINUS_INF; + Seg[0].x1 = 0; + Seg[0].Type = 6; + + Seg[0].Params[0] = 1; + Seg[0].Params[1] = 0; + Seg[0].Params[2] = 0; + Seg[0].Params[3] = values[0]; + Seg[0].Params[4] = 0; + + // From zero to 1 + Seg[1].x0 = 0; + Seg[1].x1 = 1.0; + Seg[1].Type = 0; + + Seg[1].nGridPoints = nEntries; + Seg[1].SampledPoints = (cmsFloat32Number*) values; + + // Final segment is constant = lastsample + Seg[2].x0 = 1.0; + Seg[2].x1 = PLUS_INF; + Seg[2].Type = 6; + + Seg[2].Params[0] = 1; + Seg[2].Params[1] = 0; + Seg[2].Params[2] = 0; + Seg[2].Params[3] = values[nEntries-1]; + Seg[2].Params[4] = 0; + + + return cmsBuildSegmentedToneCurve(ContextID, 3, Seg); +} + +// Parametric curves +// +// Parameters goes as: Curve, a, b, c, d, e, f +// Type is the ICC type +1 +// if type is negative, then the curve is analytically inverted +cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[]) +{ + cmsCurveSegment Seg0; + int Pos = 0; + cmsUInt32Number size; + _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos); + + _cmsAssert(Params != NULL); + + if (c == NULL) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); + return NULL; + } + + memset(&Seg0, 0, sizeof(Seg0)); + + Seg0.x0 = MINUS_INF; + Seg0.x1 = PLUS_INF; + Seg0.Type = Type; + + size = c->ParameterCount[Pos] * sizeof(cmsFloat64Number); + memmove(Seg0.Params, Params, size); + + return cmsBuildSegmentedToneCurve(ContextID, 1, &Seg0); +} + + + +// Build a gamma table based on gamma constant +cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma) +{ + return cmsBuildParametricToneCurve(ContextID, 1, &Gamma); +} + + +// Free all memory taken by the gamma curve +void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve) +{ + cmsContext ContextID; + + if (Curve == NULL) return; + + ContextID = Curve ->InterpParams->ContextID; + + _cmsFreeInterpParams(Curve ->InterpParams); + + if (Curve -> Table16) + _cmsFree(ContextID, Curve ->Table16); + + if (Curve ->Segments) { + + cmsUInt32Number i; + + for (i=0; i < Curve ->nSegments; i++) { + + if (Curve ->Segments[i].SampledPoints) { + _cmsFree(ContextID, Curve ->Segments[i].SampledPoints); + } + + if (Curve ->SegInterp[i] != 0) + _cmsFreeInterpParams(Curve->SegInterp[i]); + } + + _cmsFree(ContextID, Curve ->Segments); + _cmsFree(ContextID, Curve ->SegInterp); + } + + if (Curve -> Evals) + _cmsFree(ContextID, Curve -> Evals); + + _cmsFree(ContextID, Curve); +} + +// Utility function, free 3 gamma tables +void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]) +{ + + _cmsAssert(Curve != NULL); + + if (Curve[0] != NULL) cmsFreeToneCurve(Curve[0]); + if (Curve[1] != NULL) cmsFreeToneCurve(Curve[1]); + if (Curve[2] != NULL) cmsFreeToneCurve(Curve[2]); + + Curve[0] = Curve[1] = Curve[2] = NULL; +} + + +// Duplicate a gamma table +cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In) +{ + if (In == NULL) return NULL; + + return AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16); +} + +// Joins two curves for X and Y. Curves should be monotonic. +// We want to get +// +// y = Y^-1(X(t)) +// +cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, + const cmsToneCurve* X, + const cmsToneCurve* Y, cmsUInt32Number nResultingPoints) +{ + cmsToneCurve* out = NULL; + cmsToneCurve* Yreversed = NULL; + cmsFloat32Number t, x; + cmsFloat32Number* Res = NULL; + cmsUInt32Number i; + + + _cmsAssert(X != NULL); + _cmsAssert(Y != NULL); + + Yreversed = cmsReverseToneCurveEx(nResultingPoints, Y); + if (Yreversed == NULL) goto Error; + + Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number)); + if (Res == NULL) goto Error; + + //Iterate + for (i=0; i < nResultingPoints; i++) { + + t = (cmsFloat32Number) i / (cmsFloat32Number)(nResultingPoints-1); + x = cmsEvalToneCurveFloat(X, t); + Res[i] = cmsEvalToneCurveFloat(Yreversed, x); + } + + // Allocate space for output + out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res); + +Error: + + if (Res != NULL) _cmsFree(ContextID, Res); + if (Yreversed != NULL) cmsFreeToneCurve(Yreversed); + + return out; +} + + + +// Get the surrounding nodes. This is tricky on non-monotonic tables +static +int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const struct _cms_interp_struc* p) +{ + int i; + int y0, y1; + + // A 1 point table is not allowed + if (p -> Domain[0] < 1) return -1; + + // Let's see if ascending or descending. + if (LutTable[0] < LutTable[p ->Domain[0]]) { + + // Table is overall ascending + for (i = (int) p->Domain[0] - 1; i >= 0; --i) { + + y0 = LutTable[i]; + y1 = LutTable[i+1]; + + if (y0 <= y1) { // Increasing + if (In >= y0 && In <= y1) return i; + } + else + if (y1 < y0) { // Decreasing + if (In >= y1 && In <= y0) return i; + } + } + } + else { + // Table is overall descending + for (i=0; i < (int) p -> Domain[0]; i++) { + + y0 = LutTable[i]; + y1 = LutTable[i+1]; + + if (y0 <= y1) { // Increasing + if (In >= y0 && In <= y1) return i; + } + else + if (y1 < y0) { // Decreasing + if (In >= y1 && In <= y0) return i; + } + } + } + + return -1; +} + +// Reverse a gamma table +cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsUInt32Number nResultSamples, const cmsToneCurve* InCurve) +{ + cmsToneCurve *out; + cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2; + int i, j; + int Ascending; + + _cmsAssert(InCurve != NULL); + + // Try to reverse it analytically whatever possible + + if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && + /* InCurve -> Segments[0].Type <= 5 */ + GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) { + + return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, + -(InCurve -> Segments[0].Type), + InCurve -> Segments[0].Params); + } + + // Nope, reverse the table. + out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL); + if (out == NULL) + return NULL; + + // We want to know if this is an ascending or descending table + Ascending = !cmsIsToneCurveDescending(InCurve); + + // Iterate across Y axis + for (i=0; i < (int) nResultSamples; i++) { + + y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1); + + // Find interval in which y is within. + j = GetInterval(y, InCurve->Table16, InCurve->InterpParams); + if (j >= 0) { + + + // Get limits of interval + x1 = InCurve ->Table16[j]; + x2 = InCurve ->Table16[j+1]; + + y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1); + y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1); + + // If collapsed, then use any + if (x1 == x2) { + + out ->Table16[i] = _cmsQuickSaturateWord(Ascending ? y2 : y1); + continue; + + } else { + + // Interpolate + a = (y2 - y1) / (x2 - x1); + b = y2 - a * x2; + } + } + + out ->Table16[i] = _cmsQuickSaturateWord(a* y + b); + } + + + return out; +} + +// Reverse a gamma table +cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma) +{ + _cmsAssert(InGamma != NULL); + + return cmsReverseToneCurveEx(4096, InGamma); +} + +// From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite +// differences. in: Graphic Gems IV, Heckbert, P.S. (ed.), Academic press. +// +// Smoothing and interpolation with second differences. +// +// Input: weights (w), data (y): vector from 1 to m. +// Input: smoothing parameter (lambda), length (m). +// Output: smoothed vector (z): vector from 1 to m. + +static +cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[], + cmsFloat32Number z[], cmsFloat32Number lambda, int m) +{ + int i, i1, i2; + cmsFloat32Number *c, *d, *e; + cmsBool st; + + + c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); + d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); + e = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number)); + + if (c != NULL && d != NULL && e != NULL) { + + + d[1] = w[1] + lambda; + c[1] = -2 * lambda / d[1]; + e[1] = lambda /d[1]; + z[1] = w[1] * y[1]; + d[2] = w[2] + 5 * lambda - d[1] * c[1] * c[1]; + c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2]; + e[2] = lambda / d[2]; + z[2] = w[2] * y[2] - c[1] * z[1]; + + for (i = 3; i < m - 1; i++) { + i1 = i - 1; i2 = i - 2; + d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i]; + e[i] = lambda / d[i]; + z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2]; + } + + i1 = m - 2; i2 = m - 3; + + d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1]; + z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2]; + i1 = m - 1; i2 = m - 2; + + d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m]; + z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m]; + + for (i = m - 2; 1<= i; i--) + z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2]; + + st = TRUE; + } + else st = FALSE; + + if (c != NULL) _cmsFree(ContextID, c); + if (d != NULL) _cmsFree(ContextID, d); + if (e != NULL) _cmsFree(ContextID, e); + + return st; +} + +// Smooths a curve sampled at regular intervals. +cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda) +{ + cmsBool SuccessStatus = TRUE; + cmsFloat32Number *w, *y, *z; + cmsUInt32Number i, nItems, Zeros, Poles; + cmsBool notCheck = FALSE; + + if (Tab != NULL && Tab->InterpParams != NULL) + { + cmsContext ContextID = Tab->InterpParams->ContextID; + + if (!cmsIsToneCurveLinear(Tab)) // Only non-linear curves need smoothing + { + nItems = Tab->nEntries; + if (nItems < MAX_NODES_IN_CURVE) + { + // Allocate one more item than needed + w = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number)); + y = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number)); + z = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number)); + + if (w != NULL && y != NULL && z != NULL) // Ensure no memory allocation failure + { + memset(w, 0, (nItems + 1) * sizeof(cmsFloat32Number)); + memset(y, 0, (nItems + 1) * sizeof(cmsFloat32Number)); + memset(z, 0, (nItems + 1) * sizeof(cmsFloat32Number)); + + for (i = 0; i < nItems; i++) + { + y[i + 1] = (cmsFloat32Number)Tab->Table16[i]; + w[i + 1] = 1.0; + } + + if (lambda < 0) + { + notCheck = TRUE; + lambda = -lambda; + } + + if (smooth2(ContextID, w, y, z, (cmsFloat32Number)lambda, (int)nItems)) + { + // Do some reality - checking... + + Zeros = Poles = 0; + for (i = nItems; i > 1; --i) + { + if (z[i] == 0.) Zeros++; + if (z[i] >= 65535.) Poles++; + if (z[i] < z[i - 1]) + { + cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic."); + SuccessStatus = notCheck; + break; + } + } + + if (SuccessStatus && Zeros > (nItems / 3)) + { + cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros."); + SuccessStatus = notCheck; + } + + if (SuccessStatus && Poles > (nItems / 3)) + { + cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles."); + SuccessStatus = notCheck; + } + + if (SuccessStatus) // Seems ok + { + for (i = 0; i < nItems; i++) + { + // Clamp to cmsUInt16Number + Tab->Table16[i] = _cmsQuickSaturateWord(z[i + 1]); + } + } + } + else // Could not smooth + { + cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Function smooth2 failed."); + SuccessStatus = FALSE; + } + } + else // One or more buffers could not be allocated + { + cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Could not allocate memory."); + SuccessStatus = FALSE; + } + + if (z != NULL) + _cmsFree(ContextID, z); + + if (y != NULL) + _cmsFree(ContextID, y); + + if (w != NULL) + _cmsFree(ContextID, w); + } + else // too many items in the table + { + cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Too many points."); + SuccessStatus = FALSE; + } + } + } + else // Tab parameter or Tab->InterpParams is NULL + { + // Can't signal an error here since the ContextID is not known at this point + SuccessStatus = FALSE; + } + + return SuccessStatus; +} + +// Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting +// in a linear table. This way assures it is linear in 12 bits, which should be enough in most cases. +cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve) +{ + int i; + int diff; + + _cmsAssert(Curve != NULL); + + for (i=0; i < (int) Curve ->nEntries; i++) { + + diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries)); + if (diff > 0x0f) + return FALSE; + } + + return TRUE; +} + +// Same, but for monotonicity +cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t) +{ + cmsUInt32Number n; + int i, last; + cmsBool lDescending; + + _cmsAssert(t != NULL); + + // Degenerated curves are monotonic? Ok, let's pass them + n = t ->nEntries; + if (n < 2) return TRUE; + + // Curve direction + lDescending = cmsIsToneCurveDescending(t); + + if (lDescending) { + + last = t ->Table16[0]; + + for (i = 1; i < (int) n; i++) { + + if (t ->Table16[i] - last > 2) // We allow some ripple + return FALSE; + else + last = t ->Table16[i]; + + } + } + else { + + last = t ->Table16[n-1]; + + for (i = (int) n - 2; i >= 0; --i) { + + if (t ->Table16[i] - last > 2) + return FALSE; + else + last = t ->Table16[i]; + + } + } + + return TRUE; +} + +// Same, but for descending tables +cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + + return t ->Table16[0] > t ->Table16[t ->nEntries-1]; +} + + +// Another info fn: is out gamma table multisegment? +cmsBool CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + + return t -> nSegments > 1; +} + +cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + + if (t -> nSegments != 1) return 0; + return t ->Segments[0].Type; +} + +// We need accuracy this time +cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v) +{ + _cmsAssert(Curve != NULL); + + // Check for 16 bits table. If so, this is a limited-precision tone curve + if (Curve ->nSegments == 0) { + + cmsUInt16Number In, Out; + + In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0); + Out = cmsEvalToneCurve16(Curve, In); + + return (cmsFloat32Number) (Out / 65535.0); + } + + return (cmsFloat32Number) EvalSegmentedFn(Curve, v); +} + +// We need xput over here +cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v) +{ + cmsUInt16Number out; + + _cmsAssert(Curve != NULL); + + Curve ->InterpParams ->Interpolation.Lerp16(&v, &out, Curve ->InterpParams); + return out; +} + + +// Least squares fitting. +// A mathematical procedure for finding the best-fitting curve to a given set of points by +// minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve. +// The sum of the squares of the offsets is used instead of the offset absolute values because +// this allows the residuals to be treated as a continuous differentiable quantity. +// +// y = f(x) = x ^ g +// +// R = (yi - (xi^g)) +// R2 = (yi - (xi^g))2 +// SUM R2 = SUM (yi - (xi^g))2 +// +// dR2/dg = -2 SUM x^g log(x)(y - x^g) +// solving for dR2/dg = 0 +// +// g = 1/n * SUM(log(y) / log(x)) + +cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision) +{ + cmsFloat64Number gamma, sum, sum2; + cmsFloat64Number n, x, y, Std; + cmsUInt32Number i; + + _cmsAssert(t != NULL); + + sum = sum2 = n = 0; + + // Excluding endpoints + for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) { + + x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1); + y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x); + + // Avoid 7% on lower part to prevent + // artifacts due to linear ramps + + if (y > 0. && y < 1. && x > 0.07) { + + gamma = log(y) / log(x); + sum += gamma; + sum2 += gamma * gamma; + n++; + } + } + + // Take a look on SD to see if gamma isn't exponential at all + Std = sqrt((n * sum2 - sum * sum) / (n*(n-1))); + + if (Std > Precision) + return -1.0; + + return (sum / n); // The mean +} + + +// Retrieve parameters on one-segment tone curves + +cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t) +{ + _cmsAssert(t != NULL); + + if (t->nSegments != 1) return NULL; + return t->Segments[0].Params; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsgmt.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsgmt.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsgmt.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsgmt.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,619 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// Auxiliary: append a Lab identity after the given sequence of profiles +// and return the transform. Lab profile is closed, rest of profiles are kept open. +cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsHTRANSFORM xform; + cmsHPROFILE hLab; + cmsHPROFILE ProfileList[256]; + cmsBool BPCList[256]; + cmsFloat64Number AdaptationList[256]; + cmsUInt32Number IntentList[256]; + cmsUInt32Number i; + + // This is a rather big number and there is no need of dynamic memory + // since we are adding a profile, 254 + 1 = 255 and this is the limit + if (nProfiles > 254) return NULL; + + // The output space + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return NULL; + + // Create a copy of parameters + for (i=0; i < nProfiles; i++) { + + ProfileList[i] = hProfiles[i]; + BPCList[i] = BPC[i]; + AdaptationList[i] = AdaptationStates[i]; + IntentList[i] = Intents[i]; + } + + // Place Lab identity at chain's end. + ProfileList[nProfiles] = hLab; + BPCList[nProfiles] = 0; + AdaptationList[nProfiles] = 1.0; + IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC; + + // Create the transform + xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList, + BPCList, + IntentList, + AdaptationList, + NULL, 0, + InputFormat, + OutputFormat, + dwFlags); + + cmsCloseProfile(hLab); + + return xform; +} + + +// Compute K -> L* relationship. Flags may include black point compensation. In this case, +// the relationship is assumed from the profile with BPC to a black point zero. +static +cmsToneCurve* ComputeKToLstar(cmsContext ContextID, + cmsUInt32Number nPoints, + cmsUInt32Number nProfiles, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsToneCurve* out = NULL; + cmsUInt32Number i; + cmsHTRANSFORM xform; + cmsCIELab Lab; + cmsFloat32Number cmyk[4]; + cmsFloat32Number* SampledPoints; + + xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags); + if (xform == NULL) return NULL; + + SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number)); + if (SampledPoints == NULL) goto Error; + + for (i=0; i < nPoints; i++) { + + cmyk[0] = 0; + cmyk[1] = 0; + cmyk[2] = 0; + cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1)); + + cmsDoTransform(xform, cmyk, &Lab, 1); + SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation + } + + out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints); + +Error: + + cmsDeleteTransform(xform); + if (SampledPoints) _cmsFree(ContextID, SampledPoints); + + return out; +} + + +// Compute Black tone curve on a CMYK -> CMYK transform. This is done by +// using the proof direction on both profiles to find K->L* relationship +// then joining both curves. dwFlags may include black point compensation. +cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, + cmsUInt32Number nPoints, + cmsUInt32Number nProfiles, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsToneCurve *in, *out, *KTone; + + // Make sure CMYK -> CMYK + if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || + cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL; + + + // Make sure last is an output profile + if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL; + + // Create individual curves. BPC works also as each K to L* is + // computed as a BPC to zero black point in case of L* + in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags); + if (in == NULL) return NULL; + + out = ComputeKToLstar(ContextID, nPoints, 1, + Intents + (nProfiles - 1), + &hProfiles [nProfiles - 1], + BPC + (nProfiles - 1), + AdaptationStates + (nProfiles - 1), + dwFlags); + if (out == NULL) { + cmsFreeToneCurve(in); + return NULL; + } + + // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but + // since this is used on black-preserving LUTs, we are not losing accuracy in any case + KTone = cmsJoinToneCurve(ContextID, in, out, nPoints); + + // Get rid of components + cmsFreeToneCurve(in); cmsFreeToneCurve(out); + + // Something went wrong... + if (KTone == NULL) return NULL; + + // Make sure it is monotonic + if (!cmsIsToneCurveMonotonic(KTone)) { + cmsFreeToneCurve(KTone); + return NULL; + } + + return KTone; +} + + +// Gamut LUT Creation ----------------------------------------------------------------------------------------- + +// Used by gamut & softproofing + +typedef struct { + + cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL + cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back + cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut + + } GAMUTCHAIN; + +// This sampler does compute gamut boundaries by comparing original +// values with a transform going back and forth. Values above ERR_THERESHOLD +// of maximum are considered out of gamut. + +#define ERR_THERESHOLD 5 + + +static +int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo) +{ + GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo; + cmsCIELab LabIn1, LabOut1; + cmsCIELab LabIn2, LabOut2; + cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; + cmsFloat64Number dE1, dE2, ErrorRatio; + + // Assume in-gamut by default. + ErrorRatio = 1.0; + + // Convert input to Lab + cmsDoTransform(t -> hInput, In, &LabIn1, 1); + + // converts from PCS to colorant. This always + // does return in-gamut values, + cmsDoTransform(t -> hForward, &LabIn1, Proof, 1); + + // Now, do the inverse, from colorant to PCS. + cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1); + + memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); + + // Try again, but this time taking Check as input + cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); + cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); + + // Take difference of direct value + dE1 = cmsDeltaE(&LabIn1, &LabOut1); + + // Take difference of converted value + dE2 = cmsDeltaE(&LabIn2, &LabOut2); + + + // if dE1 is small and dE2 is small, value is likely to be in gamut + if (dE1 < t->Thereshold && dE2 < t->Thereshold) + Out[0] = 0; + else { + + // if dE1 is small and dE2 is big, undefined. Assume in gamut + if (dE1 < t->Thereshold && dE2 > t->Thereshold) + Out[0] = 0; + else + // dE1 is big and dE2 is small, clearly out of gamut + if (dE1 > t->Thereshold && dE2 < t->Thereshold) + Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); + else { + + // dE1 is big and dE2 is also big, could be due to perceptual mapping + // so take error ratio + if (dE2 == 0.0) + ErrorRatio = dE1; + else + ErrorRatio = dE1 / dE2; + + if (ErrorRatio > t->Thereshold) + Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); + else + Out[0] = 0; + } + } + + + return TRUE; +} + +// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs +// the dE obtained is then annotated on the LUT. Values truly out of gamut are clipped to dE = 0xFFFE +// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well. +// +// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors, +// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should. + +cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number nGamutPCSposition, + cmsHPROFILE hGamut) +{ + cmsHPROFILE hLab; + cmsPipeline* Gamut; + cmsStage* CLUT; + cmsUInt32Number dwFormat; + GAMUTCHAIN Chain; + cmsUInt32Number nChannels, nGridpoints; + cmsColorSpaceSignature ColorSpace; + cmsUInt32Number i; + cmsHPROFILE ProfileList[256]; + cmsBool BPCList[256]; + cmsFloat64Number AdaptationList[256]; + cmsUInt32Number IntentList[256]; + + memset(&Chain, 0, sizeof(GAMUTCHAIN)); + + + if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition); + return NULL; + } + + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return NULL; + + + // The figure of merit. On matrix-shaper profiles, should be almost zero as + // the conversion is pretty exact. On LUT based profiles, different resolutions + // of input and output CLUT may result in differences. + + if (cmsIsMatrixShaper(hGamut)) { + + Chain.Thereshold = 1.0; + } + else { + Chain.Thereshold = ERR_THERESHOLD; + } + + + // Create a copy of parameters + for (i=0; i < nGamutPCSposition; i++) { + ProfileList[i] = hProfiles[i]; + BPCList[i] = BPC[i]; + AdaptationList[i] = AdaptationStates[i]; + IntentList[i] = Intents[i]; + } + + // Fill Lab identity + ProfileList[nGamutPCSposition] = hLab; + BPCList[nGamutPCSposition] = 0; + AdaptationList[nGamutPCSposition] = 1.0; + IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; + + + ColorSpace = cmsGetColorSpace(hGamut); + + nChannels = cmsChannelsOf(ColorSpace); + nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC); + dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); + + // 16 bits to Lab double + Chain.hInput = cmsCreateExtendedTransform(ContextID, + nGamutPCSposition + 1, + ProfileList, + BPCList, + IntentList, + AdaptationList, + NULL, 0, + dwFormat, TYPE_Lab_DBL, + cmsFLAGS_NOCACHE); + + + // Does create the forward step. Lab double to device + dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); + Chain.hForward = cmsCreateTransformTHR(ContextID, + hLab, TYPE_Lab_DBL, + hGamut, dwFormat, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE); + + // Does create the backwards step + Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat, + hLab, TYPE_Lab_DBL, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE); + + + // All ok? + if (Chain.hInput && Chain.hForward && Chain.hReverse) { + + // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing + // dE when doing a transform back and forth on the colorimetric intent. + + Gamut = cmsPipelineAlloc(ContextID, 3, 1); + if (Gamut != NULL) { + + CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); + if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) { + cmsPipelineFree(Gamut); + Gamut = NULL; + } + else { + cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); + } + } + } + else + Gamut = NULL; // Didn't work... + + // Free all needed stuff. + if (Chain.hInput) cmsDeleteTransform(Chain.hInput); + if (Chain.hForward) cmsDeleteTransform(Chain.hForward); + if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse); + if (hLab) cmsCloseProfile(hLab); + + // And return computed hull + return Gamut; +} + +// Total Area Coverage estimation ---------------------------------------------------------------- + +typedef struct { + cmsUInt32Number nOutputChans; + cmsHTRANSFORM hRoundTrip; + cmsFloat32Number MaxTAC; + cmsFloat32Number MaxInput[cmsMAXCHANNELS]; + +} cmsTACestimator; + + +// This callback just accounts the maximum ink dropped in the given node. It does not populate any +// memory, as the destination table is NULL. Its only purpose it to know the global maximum. +static +int EstimateTAC(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void * Cargo) +{ + cmsTACestimator* bp = (cmsTACestimator*) Cargo; + cmsFloat32Number RoundTrip[cmsMAXCHANNELS]; + cmsUInt32Number i; + cmsFloat32Number Sum; + + + // Evaluate the xform + cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1); + + // All all amounts of ink + for (Sum=0, i=0; i < bp ->nOutputChans; i++) + Sum += RoundTrip[i]; + + // If above maximum, keep track of input values + if (Sum > bp ->MaxTAC) { + + bp ->MaxTAC = Sum; + + for (i=0; i < bp ->nOutputChans; i++) { + bp ->MaxInput[i] = In[i]; + } + } + + return TRUE; + + cmsUNUSED_PARAMETER(Out); +} + + +// Detect Total area coverage of the profile +cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) +{ + cmsTACestimator bp; + cmsUInt32Number dwFormatter; + cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS]; + cmsHPROFILE hLab; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + // TAC only works on output profiles + if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) { + return 0; + } + + // Create a fake formatter for result + dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE); + + bp.nOutputChans = T_CHANNELS(dwFormatter); + bp.MaxTAC = 0; // Initial TAC is 0 + + // for safety + if (bp.nOutputChans >= cmsMAXCHANNELS) return 0; + + hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + if (hLab == NULL) return 0; + // Setup a roundtrip on perceptual intent in output profile for TAC estimation + bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16, + hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); + + cmsCloseProfile(hLab); + if (bp.hRoundTrip == NULL) return 0; + + // For L* we only need black and white. For C* we need many points + GridPoints[0] = 6; + GridPoints[1] = 74; + GridPoints[2] = 74; + + + if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) { + bp.MaxTAC = 0; + } + + cmsDeleteTransform(bp.hRoundTrip); + + // Results in % + return bp.MaxTAC; +} + + +// Carefully, clamp on CIELab space. + +cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, + double amax, double amin, + double bmax, double bmin) +{ + + // Whole Luma surface to zero + + if (Lab -> L < 0) { + + Lab-> L = Lab->a = Lab-> b = 0.0; + return FALSE; + } + + // Clamp white, DISCARD HIGHLIGHTS. This is done + // in such way because icc spec doesn't allow the + // use of L>100 as a highlight means. + + if (Lab->L > 100) + Lab -> L = 100; + + // Check out gamut prism, on a, b faces + + if (Lab -> a < amin || Lab->a > amax|| + Lab -> b < bmin || Lab->b > bmax) { + + cmsCIELCh LCh; + double h, slope; + + // Falls outside a, b limits. Transports to LCh space, + // and then do the clipping + + + if (Lab -> a == 0.0) { // Is hue exactly 90? + + // atan will not work, so clamp here + Lab -> b = Lab->b < 0 ? bmin : bmax; + return TRUE; + } + + cmsLab2LCh(&LCh, Lab); + + slope = Lab -> b / Lab -> a; + h = LCh.h; + + // There are 4 zones + + if ((h >= 0. && h < 45.) || + (h >= 315 && h <= 360.)) { + + // clip by amax + Lab -> a = amax; + Lab -> b = amax * slope; + } + else + if (h >= 45. && h < 135.) + { + // clip by bmax + Lab -> b = bmax; + Lab -> a = bmax / slope; + } + else + if (h >= 135. && h < 225.) { + // clip by amin + Lab -> a = amin; + Lab -> b = amin * slope; + + } + else + if (h >= 225. && h < 315.) { + // clip by bmin + Lab -> b = bmin; + Lab -> a = bmin / slope; + } + else { + cmsSignalError(0, cmsERROR_RANGE, "Invalid angle"); + return FALSE; + } + + } + + return TRUE; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmshalf.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmshalf.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmshalf.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmshalf.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,564 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// +// +#include "lcms2_internal.h" + +#ifndef CMS_NO_HALF_SUPPORT + +// This code is inspired in the paper "Fast Half Float Conversions" +// by Jeroen van der Zijp + +static const cmsUInt32Number Mantissa[2048] = { + +0x00000000, 0x33800000, 0x34000000, 0x34400000, 0x34800000, 0x34a00000, +0x34c00000, 0x34e00000, 0x35000000, 0x35100000, 0x35200000, 0x35300000, +0x35400000, 0x35500000, 0x35600000, 0x35700000, 0x35800000, 0x35880000, +0x35900000, 0x35980000, 0x35a00000, 0x35a80000, 0x35b00000, 0x35b80000, +0x35c00000, 0x35c80000, 0x35d00000, 0x35d80000, 0x35e00000, 0x35e80000, +0x35f00000, 0x35f80000, 0x36000000, 0x36040000, 0x36080000, 0x360c0000, +0x36100000, 0x36140000, 0x36180000, 0x361c0000, 0x36200000, 0x36240000, +0x36280000, 0x362c0000, 0x36300000, 0x36340000, 0x36380000, 0x363c0000, +0x36400000, 0x36440000, 0x36480000, 0x364c0000, 0x36500000, 0x36540000, +0x36580000, 0x365c0000, 0x36600000, 0x36640000, 0x36680000, 0x366c0000, +0x36700000, 0x36740000, 0x36780000, 0x367c0000, 0x36800000, 0x36820000, +0x36840000, 0x36860000, 0x36880000, 0x368a0000, 0x368c0000, 0x368e0000, +0x36900000, 0x36920000, 0x36940000, 0x36960000, 0x36980000, 0x369a0000, +0x369c0000, 0x369e0000, 0x36a00000, 0x36a20000, 0x36a40000, 0x36a60000, +0x36a80000, 0x36aa0000, 0x36ac0000, 0x36ae0000, 0x36b00000, 0x36b20000, +0x36b40000, 0x36b60000, 0x36b80000, 0x36ba0000, 0x36bc0000, 0x36be0000, +0x36c00000, 0x36c20000, 0x36c40000, 0x36c60000, 0x36c80000, 0x36ca0000, +0x36cc0000, 0x36ce0000, 0x36d00000, 0x36d20000, 0x36d40000, 0x36d60000, +0x36d80000, 0x36da0000, 0x36dc0000, 0x36de0000, 0x36e00000, 0x36e20000, +0x36e40000, 0x36e60000, 0x36e80000, 0x36ea0000, 0x36ec0000, 0x36ee0000, +0x36f00000, 0x36f20000, 0x36f40000, 0x36f60000, 0x36f80000, 0x36fa0000, +0x36fc0000, 0x36fe0000, 0x37000000, 0x37010000, 0x37020000, 0x37030000, +0x37040000, 0x37050000, 0x37060000, 0x37070000, 0x37080000, 0x37090000, +0x370a0000, 0x370b0000, 0x370c0000, 0x370d0000, 0x370e0000, 0x370f0000, +0x37100000, 0x37110000, 0x37120000, 0x37130000, 0x37140000, 0x37150000, +0x37160000, 0x37170000, 0x37180000, 0x37190000, 0x371a0000, 0x371b0000, +0x371c0000, 0x371d0000, 0x371e0000, 0x371f0000, 0x37200000, 0x37210000, +0x37220000, 0x37230000, 0x37240000, 0x37250000, 0x37260000, 0x37270000, +0x37280000, 0x37290000, 0x372a0000, 0x372b0000, 0x372c0000, 0x372d0000, +0x372e0000, 0x372f0000, 0x37300000, 0x37310000, 0x37320000, 0x37330000, +0x37340000, 0x37350000, 0x37360000, 0x37370000, 0x37380000, 0x37390000, +0x373a0000, 0x373b0000, 0x373c0000, 0x373d0000, 0x373e0000, 0x373f0000, +0x37400000, 0x37410000, 0x37420000, 0x37430000, 0x37440000, 0x37450000, +0x37460000, 0x37470000, 0x37480000, 0x37490000, 0x374a0000, 0x374b0000, +0x374c0000, 0x374d0000, 0x374e0000, 0x374f0000, 0x37500000, 0x37510000, +0x37520000, 0x37530000, 0x37540000, 0x37550000, 0x37560000, 0x37570000, +0x37580000, 0x37590000, 0x375a0000, 0x375b0000, 0x375c0000, 0x375d0000, +0x375e0000, 0x375f0000, 0x37600000, 0x37610000, 0x37620000, 0x37630000, +0x37640000, 0x37650000, 0x37660000, 0x37670000, 0x37680000, 0x37690000, +0x376a0000, 0x376b0000, 0x376c0000, 0x376d0000, 0x376e0000, 0x376f0000, +0x37700000, 0x37710000, 0x37720000, 0x37730000, 0x37740000, 0x37750000, +0x37760000, 0x37770000, 0x37780000, 0x37790000, 0x377a0000, 0x377b0000, +0x377c0000, 0x377d0000, 0x377e0000, 0x377f0000, 0x37800000, 0x37808000, +0x37810000, 0x37818000, 0x37820000, 0x37828000, 0x37830000, 0x37838000, +0x37840000, 0x37848000, 0x37850000, 0x37858000, 0x37860000, 0x37868000, +0x37870000, 0x37878000, 0x37880000, 0x37888000, 0x37890000, 0x37898000, +0x378a0000, 0x378a8000, 0x378b0000, 0x378b8000, 0x378c0000, 0x378c8000, +0x378d0000, 0x378d8000, 0x378e0000, 0x378e8000, 0x378f0000, 0x378f8000, +0x37900000, 0x37908000, 0x37910000, 0x37918000, 0x37920000, 0x37928000, +0x37930000, 0x37938000, 0x37940000, 0x37948000, 0x37950000, 0x37958000, +0x37960000, 0x37968000, 0x37970000, 0x37978000, 0x37980000, 0x37988000, +0x37990000, 0x37998000, 0x379a0000, 0x379a8000, 0x379b0000, 0x379b8000, +0x379c0000, 0x379c8000, 0x379d0000, 0x379d8000, 0x379e0000, 0x379e8000, +0x379f0000, 0x379f8000, 0x37a00000, 0x37a08000, 0x37a10000, 0x37a18000, +0x37a20000, 0x37a28000, 0x37a30000, 0x37a38000, 0x37a40000, 0x37a48000, +0x37a50000, 0x37a58000, 0x37a60000, 0x37a68000, 0x37a70000, 0x37a78000, +0x37a80000, 0x37a88000, 0x37a90000, 0x37a98000, 0x37aa0000, 0x37aa8000, +0x37ab0000, 0x37ab8000, 0x37ac0000, 0x37ac8000, 0x37ad0000, 0x37ad8000, +0x37ae0000, 0x37ae8000, 0x37af0000, 0x37af8000, 0x37b00000, 0x37b08000, +0x37b10000, 0x37b18000, 0x37b20000, 0x37b28000, 0x37b30000, 0x37b38000, +0x37b40000, 0x37b48000, 0x37b50000, 0x37b58000, 0x37b60000, 0x37b68000, +0x37b70000, 0x37b78000, 0x37b80000, 0x37b88000, 0x37b90000, 0x37b98000, +0x37ba0000, 0x37ba8000, 0x37bb0000, 0x37bb8000, 0x37bc0000, 0x37bc8000, +0x37bd0000, 0x37bd8000, 0x37be0000, 0x37be8000, 0x37bf0000, 0x37bf8000, +0x37c00000, 0x37c08000, 0x37c10000, 0x37c18000, 0x37c20000, 0x37c28000, +0x37c30000, 0x37c38000, 0x37c40000, 0x37c48000, 0x37c50000, 0x37c58000, +0x37c60000, 0x37c68000, 0x37c70000, 0x37c78000, 0x37c80000, 0x37c88000, +0x37c90000, 0x37c98000, 0x37ca0000, 0x37ca8000, 0x37cb0000, 0x37cb8000, +0x37cc0000, 0x37cc8000, 0x37cd0000, 0x37cd8000, 0x37ce0000, 0x37ce8000, +0x37cf0000, 0x37cf8000, 0x37d00000, 0x37d08000, 0x37d10000, 0x37d18000, +0x37d20000, 0x37d28000, 0x37d30000, 0x37d38000, 0x37d40000, 0x37d48000, +0x37d50000, 0x37d58000, 0x37d60000, 0x37d68000, 0x37d70000, 0x37d78000, +0x37d80000, 0x37d88000, 0x37d90000, 0x37d98000, 0x37da0000, 0x37da8000, +0x37db0000, 0x37db8000, 0x37dc0000, 0x37dc8000, 0x37dd0000, 0x37dd8000, +0x37de0000, 0x37de8000, 0x37df0000, 0x37df8000, 0x37e00000, 0x37e08000, +0x37e10000, 0x37e18000, 0x37e20000, 0x37e28000, 0x37e30000, 0x37e38000, +0x37e40000, 0x37e48000, 0x37e50000, 0x37e58000, 0x37e60000, 0x37e68000, +0x37e70000, 0x37e78000, 0x37e80000, 0x37e88000, 0x37e90000, 0x37e98000, +0x37ea0000, 0x37ea8000, 0x37eb0000, 0x37eb8000, 0x37ec0000, 0x37ec8000, +0x37ed0000, 0x37ed8000, 0x37ee0000, 0x37ee8000, 0x37ef0000, 0x37ef8000, +0x37f00000, 0x37f08000, 0x37f10000, 0x37f18000, 0x37f20000, 0x37f28000, +0x37f30000, 0x37f38000, 0x37f40000, 0x37f48000, 0x37f50000, 0x37f58000, +0x37f60000, 0x37f68000, 0x37f70000, 0x37f78000, 0x37f80000, 0x37f88000, +0x37f90000, 0x37f98000, 0x37fa0000, 0x37fa8000, 0x37fb0000, 0x37fb8000, +0x37fc0000, 0x37fc8000, 0x37fd0000, 0x37fd8000, 0x37fe0000, 0x37fe8000, +0x37ff0000, 0x37ff8000, 0x38000000, 0x38004000, 0x38008000, 0x3800c000, +0x38010000, 0x38014000, 0x38018000, 0x3801c000, 0x38020000, 0x38024000, +0x38028000, 0x3802c000, 0x38030000, 0x38034000, 0x38038000, 0x3803c000, +0x38040000, 0x38044000, 0x38048000, 0x3804c000, 0x38050000, 0x38054000, +0x38058000, 0x3805c000, 0x38060000, 0x38064000, 0x38068000, 0x3806c000, +0x38070000, 0x38074000, 0x38078000, 0x3807c000, 0x38080000, 0x38084000, +0x38088000, 0x3808c000, 0x38090000, 0x38094000, 0x38098000, 0x3809c000, +0x380a0000, 0x380a4000, 0x380a8000, 0x380ac000, 0x380b0000, 0x380b4000, +0x380b8000, 0x380bc000, 0x380c0000, 0x380c4000, 0x380c8000, 0x380cc000, +0x380d0000, 0x380d4000, 0x380d8000, 0x380dc000, 0x380e0000, 0x380e4000, +0x380e8000, 0x380ec000, 0x380f0000, 0x380f4000, 0x380f8000, 0x380fc000, +0x38100000, 0x38104000, 0x38108000, 0x3810c000, 0x38110000, 0x38114000, +0x38118000, 0x3811c000, 0x38120000, 0x38124000, 0x38128000, 0x3812c000, +0x38130000, 0x38134000, 0x38138000, 0x3813c000, 0x38140000, 0x38144000, +0x38148000, 0x3814c000, 0x38150000, 0x38154000, 0x38158000, 0x3815c000, +0x38160000, 0x38164000, 0x38168000, 0x3816c000, 0x38170000, 0x38174000, +0x38178000, 0x3817c000, 0x38180000, 0x38184000, 0x38188000, 0x3818c000, +0x38190000, 0x38194000, 0x38198000, 0x3819c000, 0x381a0000, 0x381a4000, +0x381a8000, 0x381ac000, 0x381b0000, 0x381b4000, 0x381b8000, 0x381bc000, +0x381c0000, 0x381c4000, 0x381c8000, 0x381cc000, 0x381d0000, 0x381d4000, +0x381d8000, 0x381dc000, 0x381e0000, 0x381e4000, 0x381e8000, 0x381ec000, +0x381f0000, 0x381f4000, 0x381f8000, 0x381fc000, 0x38200000, 0x38204000, +0x38208000, 0x3820c000, 0x38210000, 0x38214000, 0x38218000, 0x3821c000, +0x38220000, 0x38224000, 0x38228000, 0x3822c000, 0x38230000, 0x38234000, +0x38238000, 0x3823c000, 0x38240000, 0x38244000, 0x38248000, 0x3824c000, +0x38250000, 0x38254000, 0x38258000, 0x3825c000, 0x38260000, 0x38264000, +0x38268000, 0x3826c000, 0x38270000, 0x38274000, 0x38278000, 0x3827c000, +0x38280000, 0x38284000, 0x38288000, 0x3828c000, 0x38290000, 0x38294000, +0x38298000, 0x3829c000, 0x382a0000, 0x382a4000, 0x382a8000, 0x382ac000, +0x382b0000, 0x382b4000, 0x382b8000, 0x382bc000, 0x382c0000, 0x382c4000, +0x382c8000, 0x382cc000, 0x382d0000, 0x382d4000, 0x382d8000, 0x382dc000, +0x382e0000, 0x382e4000, 0x382e8000, 0x382ec000, 0x382f0000, 0x382f4000, +0x382f8000, 0x382fc000, 0x38300000, 0x38304000, 0x38308000, 0x3830c000, +0x38310000, 0x38314000, 0x38318000, 0x3831c000, 0x38320000, 0x38324000, +0x38328000, 0x3832c000, 0x38330000, 0x38334000, 0x38338000, 0x3833c000, +0x38340000, 0x38344000, 0x38348000, 0x3834c000, 0x38350000, 0x38354000, +0x38358000, 0x3835c000, 0x38360000, 0x38364000, 0x38368000, 0x3836c000, +0x38370000, 0x38374000, 0x38378000, 0x3837c000, 0x38380000, 0x38384000, +0x38388000, 0x3838c000, 0x38390000, 0x38394000, 0x38398000, 0x3839c000, +0x383a0000, 0x383a4000, 0x383a8000, 0x383ac000, 0x383b0000, 0x383b4000, +0x383b8000, 0x383bc000, 0x383c0000, 0x383c4000, 0x383c8000, 0x383cc000, +0x383d0000, 0x383d4000, 0x383d8000, 0x383dc000, 0x383e0000, 0x383e4000, +0x383e8000, 0x383ec000, 0x383f0000, 0x383f4000, 0x383f8000, 0x383fc000, +0x38400000, 0x38404000, 0x38408000, 0x3840c000, 0x38410000, 0x38414000, +0x38418000, 0x3841c000, 0x38420000, 0x38424000, 0x38428000, 0x3842c000, +0x38430000, 0x38434000, 0x38438000, 0x3843c000, 0x38440000, 0x38444000, +0x38448000, 0x3844c000, 0x38450000, 0x38454000, 0x38458000, 0x3845c000, +0x38460000, 0x38464000, 0x38468000, 0x3846c000, 0x38470000, 0x38474000, +0x38478000, 0x3847c000, 0x38480000, 0x38484000, 0x38488000, 0x3848c000, +0x38490000, 0x38494000, 0x38498000, 0x3849c000, 0x384a0000, 0x384a4000, +0x384a8000, 0x384ac000, 0x384b0000, 0x384b4000, 0x384b8000, 0x384bc000, +0x384c0000, 0x384c4000, 0x384c8000, 0x384cc000, 0x384d0000, 0x384d4000, +0x384d8000, 0x384dc000, 0x384e0000, 0x384e4000, 0x384e8000, 0x384ec000, +0x384f0000, 0x384f4000, 0x384f8000, 0x384fc000, 0x38500000, 0x38504000, +0x38508000, 0x3850c000, 0x38510000, 0x38514000, 0x38518000, 0x3851c000, +0x38520000, 0x38524000, 0x38528000, 0x3852c000, 0x38530000, 0x38534000, +0x38538000, 0x3853c000, 0x38540000, 0x38544000, 0x38548000, 0x3854c000, +0x38550000, 0x38554000, 0x38558000, 0x3855c000, 0x38560000, 0x38564000, +0x38568000, 0x3856c000, 0x38570000, 0x38574000, 0x38578000, 0x3857c000, +0x38580000, 0x38584000, 0x38588000, 0x3858c000, 0x38590000, 0x38594000, +0x38598000, 0x3859c000, 0x385a0000, 0x385a4000, 0x385a8000, 0x385ac000, +0x385b0000, 0x385b4000, 0x385b8000, 0x385bc000, 0x385c0000, 0x385c4000, +0x385c8000, 0x385cc000, 0x385d0000, 0x385d4000, 0x385d8000, 0x385dc000, +0x385e0000, 0x385e4000, 0x385e8000, 0x385ec000, 0x385f0000, 0x385f4000, +0x385f8000, 0x385fc000, 0x38600000, 0x38604000, 0x38608000, 0x3860c000, +0x38610000, 0x38614000, 0x38618000, 0x3861c000, 0x38620000, 0x38624000, +0x38628000, 0x3862c000, 0x38630000, 0x38634000, 0x38638000, 0x3863c000, +0x38640000, 0x38644000, 0x38648000, 0x3864c000, 0x38650000, 0x38654000, +0x38658000, 0x3865c000, 0x38660000, 0x38664000, 0x38668000, 0x3866c000, +0x38670000, 0x38674000, 0x38678000, 0x3867c000, 0x38680000, 0x38684000, +0x38688000, 0x3868c000, 0x38690000, 0x38694000, 0x38698000, 0x3869c000, +0x386a0000, 0x386a4000, 0x386a8000, 0x386ac000, 0x386b0000, 0x386b4000, +0x386b8000, 0x386bc000, 0x386c0000, 0x386c4000, 0x386c8000, 0x386cc000, +0x386d0000, 0x386d4000, 0x386d8000, 0x386dc000, 0x386e0000, 0x386e4000, +0x386e8000, 0x386ec000, 0x386f0000, 0x386f4000, 0x386f8000, 0x386fc000, +0x38700000, 0x38704000, 0x38708000, 0x3870c000, 0x38710000, 0x38714000, +0x38718000, 0x3871c000, 0x38720000, 0x38724000, 0x38728000, 0x3872c000, +0x38730000, 0x38734000, 0x38738000, 0x3873c000, 0x38740000, 0x38744000, +0x38748000, 0x3874c000, 0x38750000, 0x38754000, 0x38758000, 0x3875c000, +0x38760000, 0x38764000, 0x38768000, 0x3876c000, 0x38770000, 0x38774000, +0x38778000, 0x3877c000, 0x38780000, 0x38784000, 0x38788000, 0x3878c000, +0x38790000, 0x38794000, 0x38798000, 0x3879c000, 0x387a0000, 0x387a4000, +0x387a8000, 0x387ac000, 0x387b0000, 0x387b4000, 0x387b8000, 0x387bc000, +0x387c0000, 0x387c4000, 0x387c8000, 0x387cc000, 0x387d0000, 0x387d4000, +0x387d8000, 0x387dc000, 0x387e0000, 0x387e4000, 0x387e8000, 0x387ec000, +0x387f0000, 0x387f4000, 0x387f8000, 0x387fc000, 0x38000000, 0x38002000, +0x38004000, 0x38006000, 0x38008000, 0x3800a000, 0x3800c000, 0x3800e000, +0x38010000, 0x38012000, 0x38014000, 0x38016000, 0x38018000, 0x3801a000, +0x3801c000, 0x3801e000, 0x38020000, 0x38022000, 0x38024000, 0x38026000, +0x38028000, 0x3802a000, 0x3802c000, 0x3802e000, 0x38030000, 0x38032000, +0x38034000, 0x38036000, 0x38038000, 0x3803a000, 0x3803c000, 0x3803e000, +0x38040000, 0x38042000, 0x38044000, 0x38046000, 0x38048000, 0x3804a000, +0x3804c000, 0x3804e000, 0x38050000, 0x38052000, 0x38054000, 0x38056000, +0x38058000, 0x3805a000, 0x3805c000, 0x3805e000, 0x38060000, 0x38062000, +0x38064000, 0x38066000, 0x38068000, 0x3806a000, 0x3806c000, 0x3806e000, +0x38070000, 0x38072000, 0x38074000, 0x38076000, 0x38078000, 0x3807a000, +0x3807c000, 0x3807e000, 0x38080000, 0x38082000, 0x38084000, 0x38086000, +0x38088000, 0x3808a000, 0x3808c000, 0x3808e000, 0x38090000, 0x38092000, +0x38094000, 0x38096000, 0x38098000, 0x3809a000, 0x3809c000, 0x3809e000, +0x380a0000, 0x380a2000, 0x380a4000, 0x380a6000, 0x380a8000, 0x380aa000, +0x380ac000, 0x380ae000, 0x380b0000, 0x380b2000, 0x380b4000, 0x380b6000, +0x380b8000, 0x380ba000, 0x380bc000, 0x380be000, 0x380c0000, 0x380c2000, +0x380c4000, 0x380c6000, 0x380c8000, 0x380ca000, 0x380cc000, 0x380ce000, +0x380d0000, 0x380d2000, 0x380d4000, 0x380d6000, 0x380d8000, 0x380da000, +0x380dc000, 0x380de000, 0x380e0000, 0x380e2000, 0x380e4000, 0x380e6000, +0x380e8000, 0x380ea000, 0x380ec000, 0x380ee000, 0x380f0000, 0x380f2000, +0x380f4000, 0x380f6000, 0x380f8000, 0x380fa000, 0x380fc000, 0x380fe000, +0x38100000, 0x38102000, 0x38104000, 0x38106000, 0x38108000, 0x3810a000, +0x3810c000, 0x3810e000, 0x38110000, 0x38112000, 0x38114000, 0x38116000, +0x38118000, 0x3811a000, 0x3811c000, 0x3811e000, 0x38120000, 0x38122000, +0x38124000, 0x38126000, 0x38128000, 0x3812a000, 0x3812c000, 0x3812e000, +0x38130000, 0x38132000, 0x38134000, 0x38136000, 0x38138000, 0x3813a000, +0x3813c000, 0x3813e000, 0x38140000, 0x38142000, 0x38144000, 0x38146000, +0x38148000, 0x3814a000, 0x3814c000, 0x3814e000, 0x38150000, 0x38152000, +0x38154000, 0x38156000, 0x38158000, 0x3815a000, 0x3815c000, 0x3815e000, +0x38160000, 0x38162000, 0x38164000, 0x38166000, 0x38168000, 0x3816a000, +0x3816c000, 0x3816e000, 0x38170000, 0x38172000, 0x38174000, 0x38176000, +0x38178000, 0x3817a000, 0x3817c000, 0x3817e000, 0x38180000, 0x38182000, +0x38184000, 0x38186000, 0x38188000, 0x3818a000, 0x3818c000, 0x3818e000, +0x38190000, 0x38192000, 0x38194000, 0x38196000, 0x38198000, 0x3819a000, +0x3819c000, 0x3819e000, 0x381a0000, 0x381a2000, 0x381a4000, 0x381a6000, +0x381a8000, 0x381aa000, 0x381ac000, 0x381ae000, 0x381b0000, 0x381b2000, +0x381b4000, 0x381b6000, 0x381b8000, 0x381ba000, 0x381bc000, 0x381be000, +0x381c0000, 0x381c2000, 0x381c4000, 0x381c6000, 0x381c8000, 0x381ca000, +0x381cc000, 0x381ce000, 0x381d0000, 0x381d2000, 0x381d4000, 0x381d6000, +0x381d8000, 0x381da000, 0x381dc000, 0x381de000, 0x381e0000, 0x381e2000, +0x381e4000, 0x381e6000, 0x381e8000, 0x381ea000, 0x381ec000, 0x381ee000, +0x381f0000, 0x381f2000, 0x381f4000, 0x381f6000, 0x381f8000, 0x381fa000, +0x381fc000, 0x381fe000, 0x38200000, 0x38202000, 0x38204000, 0x38206000, +0x38208000, 0x3820a000, 0x3820c000, 0x3820e000, 0x38210000, 0x38212000, +0x38214000, 0x38216000, 0x38218000, 0x3821a000, 0x3821c000, 0x3821e000, +0x38220000, 0x38222000, 0x38224000, 0x38226000, 0x38228000, 0x3822a000, +0x3822c000, 0x3822e000, 0x38230000, 0x38232000, 0x38234000, 0x38236000, +0x38238000, 0x3823a000, 0x3823c000, 0x3823e000, 0x38240000, 0x38242000, +0x38244000, 0x38246000, 0x38248000, 0x3824a000, 0x3824c000, 0x3824e000, +0x38250000, 0x38252000, 0x38254000, 0x38256000, 0x38258000, 0x3825a000, +0x3825c000, 0x3825e000, 0x38260000, 0x38262000, 0x38264000, 0x38266000, +0x38268000, 0x3826a000, 0x3826c000, 0x3826e000, 0x38270000, 0x38272000, +0x38274000, 0x38276000, 0x38278000, 0x3827a000, 0x3827c000, 0x3827e000, +0x38280000, 0x38282000, 0x38284000, 0x38286000, 0x38288000, 0x3828a000, +0x3828c000, 0x3828e000, 0x38290000, 0x38292000, 0x38294000, 0x38296000, +0x38298000, 0x3829a000, 0x3829c000, 0x3829e000, 0x382a0000, 0x382a2000, +0x382a4000, 0x382a6000, 0x382a8000, 0x382aa000, 0x382ac000, 0x382ae000, +0x382b0000, 0x382b2000, 0x382b4000, 0x382b6000, 0x382b8000, 0x382ba000, +0x382bc000, 0x382be000, 0x382c0000, 0x382c2000, 0x382c4000, 0x382c6000, +0x382c8000, 0x382ca000, 0x382cc000, 0x382ce000, 0x382d0000, 0x382d2000, +0x382d4000, 0x382d6000, 0x382d8000, 0x382da000, 0x382dc000, 0x382de000, +0x382e0000, 0x382e2000, 0x382e4000, 0x382e6000, 0x382e8000, 0x382ea000, +0x382ec000, 0x382ee000, 0x382f0000, 0x382f2000, 0x382f4000, 0x382f6000, +0x382f8000, 0x382fa000, 0x382fc000, 0x382fe000, 0x38300000, 0x38302000, +0x38304000, 0x38306000, 0x38308000, 0x3830a000, 0x3830c000, 0x3830e000, +0x38310000, 0x38312000, 0x38314000, 0x38316000, 0x38318000, 0x3831a000, +0x3831c000, 0x3831e000, 0x38320000, 0x38322000, 0x38324000, 0x38326000, +0x38328000, 0x3832a000, 0x3832c000, 0x3832e000, 0x38330000, 0x38332000, +0x38334000, 0x38336000, 0x38338000, 0x3833a000, 0x3833c000, 0x3833e000, +0x38340000, 0x38342000, 0x38344000, 0x38346000, 0x38348000, 0x3834a000, +0x3834c000, 0x3834e000, 0x38350000, 0x38352000, 0x38354000, 0x38356000, +0x38358000, 0x3835a000, 0x3835c000, 0x3835e000, 0x38360000, 0x38362000, +0x38364000, 0x38366000, 0x38368000, 0x3836a000, 0x3836c000, 0x3836e000, +0x38370000, 0x38372000, 0x38374000, 0x38376000, 0x38378000, 0x3837a000, +0x3837c000, 0x3837e000, 0x38380000, 0x38382000, 0x38384000, 0x38386000, +0x38388000, 0x3838a000, 0x3838c000, 0x3838e000, 0x38390000, 0x38392000, +0x38394000, 0x38396000, 0x38398000, 0x3839a000, 0x3839c000, 0x3839e000, +0x383a0000, 0x383a2000, 0x383a4000, 0x383a6000, 0x383a8000, 0x383aa000, +0x383ac000, 0x383ae000, 0x383b0000, 0x383b2000, 0x383b4000, 0x383b6000, +0x383b8000, 0x383ba000, 0x383bc000, 0x383be000, 0x383c0000, 0x383c2000, +0x383c4000, 0x383c6000, 0x383c8000, 0x383ca000, 0x383cc000, 0x383ce000, +0x383d0000, 0x383d2000, 0x383d4000, 0x383d6000, 0x383d8000, 0x383da000, +0x383dc000, 0x383de000, 0x383e0000, 0x383e2000, 0x383e4000, 0x383e6000, +0x383e8000, 0x383ea000, 0x383ec000, 0x383ee000, 0x383f0000, 0x383f2000, +0x383f4000, 0x383f6000, 0x383f8000, 0x383fa000, 0x383fc000, 0x383fe000, +0x38400000, 0x38402000, 0x38404000, 0x38406000, 0x38408000, 0x3840a000, +0x3840c000, 0x3840e000, 0x38410000, 0x38412000, 0x38414000, 0x38416000, +0x38418000, 0x3841a000, 0x3841c000, 0x3841e000, 0x38420000, 0x38422000, +0x38424000, 0x38426000, 0x38428000, 0x3842a000, 0x3842c000, 0x3842e000, +0x38430000, 0x38432000, 0x38434000, 0x38436000, 0x38438000, 0x3843a000, +0x3843c000, 0x3843e000, 0x38440000, 0x38442000, 0x38444000, 0x38446000, +0x38448000, 0x3844a000, 0x3844c000, 0x3844e000, 0x38450000, 0x38452000, +0x38454000, 0x38456000, 0x38458000, 0x3845a000, 0x3845c000, 0x3845e000, +0x38460000, 0x38462000, 0x38464000, 0x38466000, 0x38468000, 0x3846a000, +0x3846c000, 0x3846e000, 0x38470000, 0x38472000, 0x38474000, 0x38476000, +0x38478000, 0x3847a000, 0x3847c000, 0x3847e000, 0x38480000, 0x38482000, +0x38484000, 0x38486000, 0x38488000, 0x3848a000, 0x3848c000, 0x3848e000, +0x38490000, 0x38492000, 0x38494000, 0x38496000, 0x38498000, 0x3849a000, +0x3849c000, 0x3849e000, 0x384a0000, 0x384a2000, 0x384a4000, 0x384a6000, +0x384a8000, 0x384aa000, 0x384ac000, 0x384ae000, 0x384b0000, 0x384b2000, +0x384b4000, 0x384b6000, 0x384b8000, 0x384ba000, 0x384bc000, 0x384be000, +0x384c0000, 0x384c2000, 0x384c4000, 0x384c6000, 0x384c8000, 0x384ca000, +0x384cc000, 0x384ce000, 0x384d0000, 0x384d2000, 0x384d4000, 0x384d6000, +0x384d8000, 0x384da000, 0x384dc000, 0x384de000, 0x384e0000, 0x384e2000, +0x384e4000, 0x384e6000, 0x384e8000, 0x384ea000, 0x384ec000, 0x384ee000, +0x384f0000, 0x384f2000, 0x384f4000, 0x384f6000, 0x384f8000, 0x384fa000, +0x384fc000, 0x384fe000, 0x38500000, 0x38502000, 0x38504000, 0x38506000, +0x38508000, 0x3850a000, 0x3850c000, 0x3850e000, 0x38510000, 0x38512000, +0x38514000, 0x38516000, 0x38518000, 0x3851a000, 0x3851c000, 0x3851e000, +0x38520000, 0x38522000, 0x38524000, 0x38526000, 0x38528000, 0x3852a000, +0x3852c000, 0x3852e000, 0x38530000, 0x38532000, 0x38534000, 0x38536000, +0x38538000, 0x3853a000, 0x3853c000, 0x3853e000, 0x38540000, 0x38542000, +0x38544000, 0x38546000, 0x38548000, 0x3854a000, 0x3854c000, 0x3854e000, +0x38550000, 0x38552000, 0x38554000, 0x38556000, 0x38558000, 0x3855a000, +0x3855c000, 0x3855e000, 0x38560000, 0x38562000, 0x38564000, 0x38566000, +0x38568000, 0x3856a000, 0x3856c000, 0x3856e000, 0x38570000, 0x38572000, +0x38574000, 0x38576000, 0x38578000, 0x3857a000, 0x3857c000, 0x3857e000, +0x38580000, 0x38582000, 0x38584000, 0x38586000, 0x38588000, 0x3858a000, +0x3858c000, 0x3858e000, 0x38590000, 0x38592000, 0x38594000, 0x38596000, +0x38598000, 0x3859a000, 0x3859c000, 0x3859e000, 0x385a0000, 0x385a2000, +0x385a4000, 0x385a6000, 0x385a8000, 0x385aa000, 0x385ac000, 0x385ae000, +0x385b0000, 0x385b2000, 0x385b4000, 0x385b6000, 0x385b8000, 0x385ba000, +0x385bc000, 0x385be000, 0x385c0000, 0x385c2000, 0x385c4000, 0x385c6000, +0x385c8000, 0x385ca000, 0x385cc000, 0x385ce000, 0x385d0000, 0x385d2000, +0x385d4000, 0x385d6000, 0x385d8000, 0x385da000, 0x385dc000, 0x385de000, +0x385e0000, 0x385e2000, 0x385e4000, 0x385e6000, 0x385e8000, 0x385ea000, +0x385ec000, 0x385ee000, 0x385f0000, 0x385f2000, 0x385f4000, 0x385f6000, +0x385f8000, 0x385fa000, 0x385fc000, 0x385fe000, 0x38600000, 0x38602000, +0x38604000, 0x38606000, 0x38608000, 0x3860a000, 0x3860c000, 0x3860e000, +0x38610000, 0x38612000, 0x38614000, 0x38616000, 0x38618000, 0x3861a000, +0x3861c000, 0x3861e000, 0x38620000, 0x38622000, 0x38624000, 0x38626000, +0x38628000, 0x3862a000, 0x3862c000, 0x3862e000, 0x38630000, 0x38632000, +0x38634000, 0x38636000, 0x38638000, 0x3863a000, 0x3863c000, 0x3863e000, +0x38640000, 0x38642000, 0x38644000, 0x38646000, 0x38648000, 0x3864a000, +0x3864c000, 0x3864e000, 0x38650000, 0x38652000, 0x38654000, 0x38656000, +0x38658000, 0x3865a000, 0x3865c000, 0x3865e000, 0x38660000, 0x38662000, +0x38664000, 0x38666000, 0x38668000, 0x3866a000, 0x3866c000, 0x3866e000, +0x38670000, 0x38672000, 0x38674000, 0x38676000, 0x38678000, 0x3867a000, +0x3867c000, 0x3867e000, 0x38680000, 0x38682000, 0x38684000, 0x38686000, +0x38688000, 0x3868a000, 0x3868c000, 0x3868e000, 0x38690000, 0x38692000, +0x38694000, 0x38696000, 0x38698000, 0x3869a000, 0x3869c000, 0x3869e000, +0x386a0000, 0x386a2000, 0x386a4000, 0x386a6000, 0x386a8000, 0x386aa000, +0x386ac000, 0x386ae000, 0x386b0000, 0x386b2000, 0x386b4000, 0x386b6000, +0x386b8000, 0x386ba000, 0x386bc000, 0x386be000, 0x386c0000, 0x386c2000, +0x386c4000, 0x386c6000, 0x386c8000, 0x386ca000, 0x386cc000, 0x386ce000, +0x386d0000, 0x386d2000, 0x386d4000, 0x386d6000, 0x386d8000, 0x386da000, +0x386dc000, 0x386de000, 0x386e0000, 0x386e2000, 0x386e4000, 0x386e6000, +0x386e8000, 0x386ea000, 0x386ec000, 0x386ee000, 0x386f0000, 0x386f2000, +0x386f4000, 0x386f6000, 0x386f8000, 0x386fa000, 0x386fc000, 0x386fe000, +0x38700000, 0x38702000, 0x38704000, 0x38706000, 0x38708000, 0x3870a000, +0x3870c000, 0x3870e000, 0x38710000, 0x38712000, 0x38714000, 0x38716000, +0x38718000, 0x3871a000, 0x3871c000, 0x3871e000, 0x38720000, 0x38722000, +0x38724000, 0x38726000, 0x38728000, 0x3872a000, 0x3872c000, 0x3872e000, +0x38730000, 0x38732000, 0x38734000, 0x38736000, 0x38738000, 0x3873a000, +0x3873c000, 0x3873e000, 0x38740000, 0x38742000, 0x38744000, 0x38746000, +0x38748000, 0x3874a000, 0x3874c000, 0x3874e000, 0x38750000, 0x38752000, +0x38754000, 0x38756000, 0x38758000, 0x3875a000, 0x3875c000, 0x3875e000, +0x38760000, 0x38762000, 0x38764000, 0x38766000, 0x38768000, 0x3876a000, +0x3876c000, 0x3876e000, 0x38770000, 0x38772000, 0x38774000, 0x38776000, +0x38778000, 0x3877a000, 0x3877c000, 0x3877e000, 0x38780000, 0x38782000, +0x38784000, 0x38786000, 0x38788000, 0x3878a000, 0x3878c000, 0x3878e000, +0x38790000, 0x38792000, 0x38794000, 0x38796000, 0x38798000, 0x3879a000, +0x3879c000, 0x3879e000, 0x387a0000, 0x387a2000, 0x387a4000, 0x387a6000, +0x387a8000, 0x387aa000, 0x387ac000, 0x387ae000, 0x387b0000, 0x387b2000, +0x387b4000, 0x387b6000, 0x387b8000, 0x387ba000, 0x387bc000, 0x387be000, +0x387c0000, 0x387c2000, 0x387c4000, 0x387c6000, 0x387c8000, 0x387ca000, +0x387cc000, 0x387ce000, 0x387d0000, 0x387d2000, 0x387d4000, 0x387d6000, +0x387d8000, 0x387da000, 0x387dc000, 0x387de000, 0x387e0000, 0x387e2000, +0x387e4000, 0x387e6000, 0x387e8000, 0x387ea000, 0x387ec000, 0x387ee000, +0x387f0000, 0x387f2000, 0x387f4000, 0x387f6000, 0x387f8000, 0x387fa000, +0x387fc000, 0x387fe000 +}; + +static cmsUInt16Number Offset[64] = { +0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0000, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, +0x0400, 0x0400, 0x0400, 0x0400 +}; + +static const cmsUInt32Number Exponent[64] = { +0x00000000, 0x00800000, 0x01000000, 0x01800000, 0x02000000, 0x02800000, +0x03000000, 0x03800000, 0x04000000, 0x04800000, 0x05000000, 0x05800000, +0x06000000, 0x06800000, 0x07000000, 0x07800000, 0x08000000, 0x08800000, +0x09000000, 0x09800000, 0x0a000000, 0x0a800000, 0x0b000000, 0x0b800000, +0x0c000000, 0x0c800000, 0x0d000000, 0x0d800000, 0x0e000000, 0x0e800000, +0x0f000000, 0x47800000, 0x80000000, 0x80800000, 0x81000000, 0x81800000, +0x82000000, 0x82800000, 0x83000000, 0x83800000, 0x84000000, 0x84800000, +0x85000000, 0x85800000, 0x86000000, 0x86800000, 0x87000000, 0x87800000, +0x88000000, 0x88800000, 0x89000000, 0x89800000, 0x8a000000, 0x8a800000, +0x8b000000, 0x8b800000, 0x8c000000, 0x8c800000, 0x8d000000, 0x8d800000, +0x8e000000, 0x8e800000, 0x8f000000, 0xc7800000 +}; + +static const cmsUInt16Number Base[512] = { +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, +0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, +0x2000, 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x4400, +0x4800, 0x4c00, 0x5000, 0x5400, 0x5800, 0x5c00, 0x6000, 0x6400, 0x6800, 0x6c00, +0x7000, 0x7400, 0x7800, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, +0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x7c00, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, +0x8002, 0x8004, 0x8008, 0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400, +0x8800, 0x8c00, 0x9000, 0x9400, 0x9800, 0x9c00, 0xa000, 0xa400, 0xa800, 0xac00, +0xb000, 0xb400, 0xb800, 0xbc00, 0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, +0xd800, 0xdc00, 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, 0xfc00, +0xfc00, 0xfc00 +}; + +static const cmsUInt8Number Shift[512] = { +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, +0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, +0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, +0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0d, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, +0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, +0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, +0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x0d +}; + +cmsFloat32Number CMSEXPORT _cmsHalf2Float(cmsUInt16Number h) +{ + union { + cmsFloat32Number flt; + cmsUInt32Number num; + } out; + + int n = h >> 10; + + out.num = Mantissa[ (h & 0x3ff) + Offset[ n ] ] + Exponent[ n ]; + return out.flt; +} + +cmsUInt16Number CMSEXPORT _cmsFloat2Half(cmsFloat32Number flt) +{ + union { + cmsFloat32Number flt; + cmsUInt32Number num; + } in; + + cmsUInt32Number n, j; + + in.flt = flt; + n = in.num; + j = (n >> 23) & 0x1ff; + + return (cmsUInt16Number) ((cmsUInt32Number) Base[ j ] + (( n & 0x007fffff) >> Shift[ j ])); +} + +#endif diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsintrp.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsintrp.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsintrp.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsintrp.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1345 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// This module incorporates several interpolation routines, for 1 to 8 channels on input and +// up to 65535 channels on output. The user may change those by using the interpolation plug-in + +// Some people may want to compile as C++ with all warnings on, in this case make compiler silent +#ifdef _MSC_VER +# if (_MSC_VER >= 1400) +# pragma warning( disable : 4365 ) +# endif +#endif + +// Interpolation routines by default +static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); + +// This is the default factory +_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL }; + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + void* from; + + _cmsAssert(ctx != NULL); + + if (src != NULL) { + from = src ->chunks[InterpPlugin]; + } + else { + static _cmsInterpPluginChunkType InterpPluginChunk = { NULL }; + + from = &InterpPluginChunk; + } + + _cmsAssert(from != NULL); + ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType)); +} + + +// Main plug-in entry +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data; + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); + + if (Data == NULL) { + + ptr ->Interpolators = NULL; + return TRUE; + } + + // Set replacement functions + ptr ->Interpolators = Plugin ->InterpolatorsFactory; + return TRUE; +} + + +// Set the interpolation method +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p) +{ + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); + + p ->Interpolation.Lerp16 = NULL; + + // Invoke factory, possibly in the Plug-in + if (ptr ->Interpolators != NULL) + p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); + + // If unsupported by the plug-in, go for the LittleCMS default. + // If happens only if an extern plug-in is being used + if (p ->Interpolation.Lerp16 == NULL) + p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags); + + // Check for valid interpolator (we just check one member of the union) + if (p ->Interpolation.Lerp16 == NULL) { + return FALSE; + } + + return TRUE; +} + + +// This function precalculates as many parameters as possible to speed up the interpolation. +cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, + const cmsUInt32Number nSamples[], + cmsUInt32Number InputChan, cmsUInt32Number OutputChan, + const void *Table, + cmsUInt32Number dwFlags) +{ + cmsInterpParams* p; + cmsUInt32Number i; + + // Check for maximum inputs + if (InputChan > MAX_INPUT_DIMENSIONS) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS); + return NULL; + } + + // Creates an empty object + p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams)); + if (p == NULL) return NULL; + + // Keep original parameters + p -> dwFlags = dwFlags; + p -> nInputs = InputChan; + p -> nOutputs = OutputChan; + p ->Table = Table; + p ->ContextID = ContextID; + + // Fill samples per input direction and domain (which is number of nodes minus one) + for (i=0; i < InputChan; i++) { + + p -> nSamples[i] = nSamples[i]; + p -> Domain[i] = nSamples[i] - 1; + } + + // Compute factors to apply to each component to index the grid array + p -> opta[0] = p -> nOutputs; + for (i=1; i < InputChan; i++) + p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i]; + + + if (!_cmsSetInterpolationRoutine(ContextID, p)) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); + _cmsFree(ContextID, p); + return NULL; + } + + // All seems ok + return p; +} + + +// This one is a wrapper on the anterior, but assuming all directions have same number of nodes +cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples, + cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags) +{ + int i; + cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS]; + + // Fill the auxiliary array + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + Samples[i] = nSamples; + + // Call the extended function + return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags); +} + + +// Free all associated memory +void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p) +{ + if (p != NULL) _cmsFree(p ->ContextID, p); +} + + +// Inline fixed point interpolation +cmsINLINE CMS_NO_SANITIZE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h) +{ + cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000; + dif = (dif >> 16) + l; + return (cmsUInt16Number) (dif); +} + + +// Linear interpolation (Fixed-point optimized) +static +void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const cmsInterpParams* p) +{ + cmsUInt16Number y1, y0; + int cell0, rest; + int val3; + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; + + // if last value... + if (Value[0] == 0xffff) { + + Output[0] = LutTable[p -> Domain[0]]; + } + else + { + val3 = p->Domain[0] * Value[0]; + val3 = _cmsToFixedDomain(val3); // To fixed 15.16 + + cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits + rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits + + y0 = LutTable[cell0]; + y1 = LutTable[cell0 + 1]; + + Output[0] = LinearInterp(rest, y0, y1); + } +} + +// To prevent out of bounds indexing +cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v) +{ + return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v); +} + +// Floating-point version of 1D interpolation +static +void LinLerp1Dfloat(const cmsFloat32Number Value[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + cmsFloat32Number y1, y0; + cmsFloat32Number val2, rest; + int cell0, cell1; + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + + val2 = fclamp(Value[0]); + + // if last value... + if (val2 == 1.0) { + Output[0] = LutTable[p -> Domain[0]]; + } + else + { + val2 *= p->Domain[0]; + + cell0 = (int)floor(val2); + cell1 = (int)ceil(val2); + + // Rest is 16 LSB bits + rest = val2 - cell0; + + y0 = LutTable[cell0]; + y1 = LutTable[cell1]; + + Output[0] = y0 + (y1 - y0) * rest; + } +} + + + +// Eval gray LUT having only one input channel +static CMS_NO_SANITIZE +void Eval1Input(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const cmsInterpParams* p16) +{ + cmsS15Fixed16Number fk; + cmsS15Fixed16Number k0, k1, rk, K0, K1; + int v; + cmsUInt32Number OutChan; + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; + + v = Input[0] * p16 -> Domain[0]; + fk = _cmsToFixedDomain(v); + + k0 = FIXED_TO_INT(fk); + rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk); + + k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0); + + K0 = p16 -> opta[0] * k0; + K1 = p16 -> opta[0] * k1; + + for (OutChan=0; OutChan < p16->nOutputs; OutChan++) { + + Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]); + } +} + + + +// Eval gray LUT having only one input channel +static +void Eval1InputFloat(const cmsFloat32Number Value[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + cmsFloat32Number y1, y0; + cmsFloat32Number val2, rest; + int cell0, cell1; + cmsUInt32Number OutChan; + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + + val2 = fclamp(Value[0]); + + // if last value... + if (val2 == 1.0) { + + y0 = LutTable[p->Domain[0]]; + + for (OutChan = 0; OutChan < p->nOutputs; OutChan++) { + Output[OutChan] = y0; + } + } + else + { + val2 *= p->Domain[0]; + + cell0 = (int)floor(val2); + cell1 = (int)ceil(val2); + + // Rest is 16 LSB bits + rest = val2 - cell0; + + cell0 *= p->opta[0]; + cell1 *= p->opta[0]; + + for (OutChan = 0; OutChan < p->nOutputs; OutChan++) { + + y0 = LutTable[cell0 + OutChan]; + y1 = LutTable[cell1 + OutChan]; + + Output[OutChan] = y0 + (y1 - y0) * rest; + } + } +} + +// Bilinear interpolation (16 bits) - cmsFloat32Number version +static +void BilinearInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) + +{ +# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) +# define DENS(i,j) (LutTable[(i)+(j)+OutChan]) + + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + cmsFloat32Number px, py; + int x0, y0, + X0, Y0, X1, Y1; + int TotalOut, OutChan; + cmsFloat32Number fx, fy, + d00, d01, d10, d11, + dx0, dx1, + dxy; + + TotalOut = p -> nOutputs; + px = fclamp(Input[0]) * p->Domain[0]; + py = fclamp(Input[1]) * p->Domain[1]; + + x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; + y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; + + X0 = p -> opta[1] * x0; + X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[1]); + + Y0 = p -> opta[0] * y0; + Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[0]); + + for (OutChan = 0; OutChan < TotalOut; OutChan++) { + + d00 = DENS(X0, Y0); + d01 = DENS(X0, Y1); + d10 = DENS(X1, Y0); + d11 = DENS(X1, Y1); + + dx0 = LERP(fx, d00, d10); + dx1 = LERP(fx, d01, d11); + + dxy = LERP(fy, dx0, dx1); + + Output[OutChan] = dxy; + } + + +# undef LERP +# undef DENS +} + +// Bilinear interpolation (16 bits) - optimized version +static CMS_NO_SANITIZE +void BilinearInterp16(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const cmsInterpParams* p) + +{ +#define DENS(i,j) (LutTable[(i)+(j)+OutChan]) +#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) + + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; + int OutChan, TotalOut; + cmsS15Fixed16Number fx, fy; + CMSREGISTER int rx, ry; + int x0, y0; + CMSREGISTER int X0, X1, Y0, Y1; + + int d00, d01, d10, d11, + dx0, dx1, + dxy; + + TotalOut = p -> nOutputs; + + fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); + x0 = FIXED_TO_INT(fx); + rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain + + + fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); + y0 = FIXED_TO_INT(fy); + ry = FIXED_REST_TO_INT(fy); + + + X0 = p -> opta[1] * x0; + X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]); + + Y0 = p -> opta[0] * y0; + Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]); + + for (OutChan = 0; OutChan < TotalOut; OutChan++) { + + d00 = DENS(X0, Y0); + d01 = DENS(X0, Y1); + d10 = DENS(X1, Y0); + d11 = DENS(X1, Y1); + + dx0 = LERP(rx, d00, d10); + dx1 = LERP(rx, d01, d11); + + dxy = LERP(ry, dx0, dx1); + + Output[OutChan] = (cmsUInt16Number) dxy; + } + + +# undef LERP +# undef DENS +} + + +// Trilinear interpolation (16 bits) - cmsFloat32Number version +static +void TrilinearInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) + +{ +# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) +# define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) + + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; + cmsFloat32Number px, py, pz; + int x0, y0, z0, + X0, Y0, Z0, X1, Y1, Z1; + int TotalOut, OutChan; + + cmsFloat32Number fx, fy, fz, + d000, d001, d010, d011, + d100, d101, d110, d111, + dx00, dx01, dx10, dx11, + dxy0, dxy1, dxyz; + + TotalOut = p -> nOutputs; + + // We need some clipping here + px = fclamp(Input[0]) * p->Domain[0]; + py = fclamp(Input[1]) * p->Domain[1]; + pz = fclamp(Input[2]) * p->Domain[2]; + + x0 = (int) floor(px); fx = px - (cmsFloat32Number) x0; // We need full floor funcionality here + y0 = (int) floor(py); fy = py - (cmsFloat32Number) y0; + z0 = (int) floor(pz); fz = pz - (cmsFloat32Number) z0; + + X0 = p -> opta[2] * x0; + X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]); + + Y0 = p -> opta[1] * y0; + Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]); + + Z0 = p -> opta[0] * z0; + Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]); + + for (OutChan = 0; OutChan < TotalOut; OutChan++) { + + d000 = DENS(X0, Y0, Z0); + d001 = DENS(X0, Y0, Z1); + d010 = DENS(X0, Y1, Z0); + d011 = DENS(X0, Y1, Z1); + + d100 = DENS(X1, Y0, Z0); + d101 = DENS(X1, Y0, Z1); + d110 = DENS(X1, Y1, Z0); + d111 = DENS(X1, Y1, Z1); + + + dx00 = LERP(fx, d000, d100); + dx01 = LERP(fx, d001, d101); + dx10 = LERP(fx, d010, d110); + dx11 = LERP(fx, d011, d111); + + dxy0 = LERP(fy, dx00, dx10); + dxy1 = LERP(fy, dx01, dx11); + + dxyz = LERP(fz, dxy0, dxy1); + + Output[OutChan] = dxyz; + } + + +# undef LERP +# undef DENS +} + +// Trilinear interpolation (16 bits) - optimized version +static CMS_NO_SANITIZE +void TrilinearInterp16(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const cmsInterpParams* p) + +{ +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) +#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) + + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; + int OutChan, TotalOut; + cmsS15Fixed16Number fx, fy, fz; + CMSREGISTER int rx, ry, rz; + int x0, y0, z0; + CMSREGISTER int X0, X1, Y0, Y1, Z0, Z1; + int d000, d001, d010, d011, + d100, d101, d110, d111, + dx00, dx01, dx10, dx11, + dxy0, dxy1, dxyz; + + TotalOut = p -> nOutputs; + + fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); + x0 = FIXED_TO_INT(fx); + rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain + + + fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); + y0 = FIXED_TO_INT(fy); + ry = FIXED_REST_TO_INT(fy); + + fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); + z0 = FIXED_TO_INT(fz); + rz = FIXED_REST_TO_INT(fz); + + + X0 = p -> opta[2] * x0; + X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]); + + Y0 = p -> opta[1] * y0; + Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]); + + Z0 = p -> opta[0] * z0; + Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]); + + for (OutChan = 0; OutChan < TotalOut; OutChan++) { + + d000 = DENS(X0, Y0, Z0); + d001 = DENS(X0, Y0, Z1); + d010 = DENS(X0, Y1, Z0); + d011 = DENS(X0, Y1, Z1); + + d100 = DENS(X1, Y0, Z0); + d101 = DENS(X1, Y0, Z1); + d110 = DENS(X1, Y1, Z0); + d111 = DENS(X1, Y1, Z1); + + + dx00 = LERP(rx, d000, d100); + dx01 = LERP(rx, d001, d101); + dx10 = LERP(rx, d010, d110); + dx11 = LERP(rx, d011, d111); + + dxy0 = LERP(ry, dx00, dx10); + dxy1 = LERP(ry, dx01, dx11); + + dxyz = LERP(rz, dxy0, dxy1); + + Output[OutChan] = (cmsUInt16Number) dxyz; + } + + +# undef LERP +# undef DENS +} + + +// Tetrahedral interpolation, using Sakamoto algorithm. +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) +static +void TetrahedralInterpFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + cmsFloat32Number px, py, pz; + int x0, y0, z0, + X0, Y0, Z0, X1, Y1, Z1; + cmsFloat32Number rx, ry, rz; + cmsFloat32Number c0, c1=0, c2=0, c3=0; + int OutChan, TotalOut; + + TotalOut = p -> nOutputs; + + // We need some clipping here + px = fclamp(Input[0]) * p->Domain[0]; + py = fclamp(Input[1]) * p->Domain[1]; + pz = fclamp(Input[2]) * p->Domain[2]; + + x0 = (int) floor(px); rx = (px - (cmsFloat32Number) x0); // We need full floor functionality here + y0 = (int) floor(py); ry = (py - (cmsFloat32Number) y0); + z0 = (int) floor(pz); rz = (pz - (cmsFloat32Number) z0); + + + X0 = p -> opta[2] * x0; + X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]); + + Y0 = p -> opta[1] * y0; + Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]); + + Z0 = p -> opta[0] * z0; + Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]); + + for (OutChan=0; OutChan < TotalOut; OutChan++) { + + // These are the 6 Tetrahedral + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (rx >= rz && rz >= ry) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + + } + else + if (rz >= rx && rx >= ry) { + + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else + if (ry >= rx && rx >= rz) { + + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (ry >= rz && rz >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + + } + else + if (rz >= ry && ry >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else { + c1 = c2 = c3 = 0; + } + + Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz; + } + +} + +#undef DENS + +static CMS_NO_SANITIZE +void TetrahedralInterp16(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const cmsInterpParams* p) +{ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table; + cmsS15Fixed16Number fx, fy, fz; + cmsS15Fixed16Number rx, ry, rz; + int x0, y0, z0; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + cmsUInt32Number X0, X1, Y0, Y1, Z0, Z1; + cmsUInt32Number TotalOut = p -> nOutputs; + + fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); + fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); + fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); + + x0 = FIXED_TO_INT(fx); + y0 = FIXED_TO_INT(fy); + z0 = FIXED_TO_INT(fz); + + rx = FIXED_REST_TO_INT(fx); + ry = FIXED_REST_TO_INT(fy); + rz = FIXED_REST_TO_INT(fz); + + X0 = p -> opta[2] * x0; + X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]); + + Y0 = p -> opta[1] * y0; + Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]); + + Z0 = p -> opta[0] * z0; + Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]); + + LutTable += X0+Y0+Z0; + + // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)) + // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16 + // This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16 + // at the cost of being off by one at 7fff and 17ffe. + + if (rx >= ry) { + if (ry >= rz) { + Y1 += X1; + Z1 += Y1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c3 -= c2; + c2 -= c1; + c1 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } else if (rz >= rx) { + X1 += Z1; + Y1 += X1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c2 -= c1; + c1 -= c3; + c3 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } else { + Z1 += X1; + Y1 += Z1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c2 -= c3; + c3 -= c1; + c1 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } + } else { + if (rx >= rz) { + X1 += Y1; + Z1 += X1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c3 -= c1; + c1 -= c2; + c2 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } else if (ry >= rz) { + Z1 += Y1; + X1 += Z1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c1 -= c3; + c3 -= c2; + c2 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } else { + Y1 += Z1; + X1 += Y1; + for (; TotalOut; TotalOut--) { + c1 = LutTable[X1]; + c2 = LutTable[Y1]; + c3 = LutTable[Z1]; + c0 = *LutTable++; + c1 -= c2; + c2 -= c3; + c3 -= c0; + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); + } + } + } +} + + +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) +static CMS_NO_SANITIZE +void Eval4Inputs(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const cmsInterpParams* p16) +{ + const cmsUInt16Number* LutTable; + cmsS15Fixed16Number fk; + cmsS15Fixed16Number k0, rk; + int K0, K1; + cmsS15Fixed16Number fx, fy, fz; + cmsS15Fixed16Number rx, ry, rz; + int x0, y0, z0; + cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; + cmsUInt32Number i; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + cmsUInt32Number OutChan; + cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + + + fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]); + fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]); + fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]); + fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]); + + k0 = FIXED_TO_INT(fk); + x0 = FIXED_TO_INT(fx); + y0 = FIXED_TO_INT(fy); + z0 = FIXED_TO_INT(fz); + + rk = FIXED_REST_TO_INT(fk); + rx = FIXED_REST_TO_INT(fx); + ry = FIXED_REST_TO_INT(fy); + rz = FIXED_REST_TO_INT(fz); + + K0 = p16 -> opta[3] * k0; + K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]); + + X0 = p16 -> opta[2] * x0; + X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]); + + Y0 = p16 -> opta[1] * y0; + Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]); + + Z0 = p16 -> opta[0] * z0; + Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]); + + LutTable = (cmsUInt16Number*) p16 -> Table; + LutTable += K0; + + for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) { + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (rx >= rz && rz >= ry) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + + } + else + if (rz >= rx && rx >= ry) { + + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else + if (ry >= rx && rx >= rz) { + + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (ry >= rz && rz >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + + } + else + if (rz >= ry && ry >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else { + c1 = c2 = c3 = 0; + } + + Rest = c1 * rx + c2 * ry + c3 * rz; + + Tmp1[OutChan] = (cmsUInt16Number)(c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))); + } + + + LutTable = (cmsUInt16Number*) p16 -> Table; + LutTable += K1; + + for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) { + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (rx >= rz && rz >= ry) { + + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + + } + else + if (rz >= rx && rx >= ry) { + + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else + if (ry >= rx && rx >= rz) { + + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + + } + else + if (ry >= rz && rz >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + + } + else + if (rz >= ry && ry >= rx) { + + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + + } + else { + c1 = c2 = c3 = 0; + } + + Rest = c1 * rx + c2 * ry + c3 * rz; + + Tmp2[OutChan] = (cmsUInt16Number) (c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))); + } + + + + for (i=0; i < p16 -> nOutputs; i++) { + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); + } +} +#undef DENS + + +// For more that 3 inputs (i.e., CMYK) +// evaluate two 3-dimensional interpolations and then linearly interpolate between them. +static +void Eval4InputsFloat(const cmsFloat32Number Input[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; + cmsFloat32Number rest; + cmsFloat32Number pk; + int k0, K0, K1; + const cmsFloat32Number* T; + cmsUInt32Number i; + cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; + cmsInterpParams p1; + + pk = fclamp(Input[0]) * p->Domain[0]; + k0 = _cmsQuickFloor(pk); + rest = pk - (cmsFloat32Number) k0; + + K0 = p -> opta[3] * k0; + K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[3]); + + p1 = *p; + memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number)); + + T = LutTable + K0; + p1.Table = T; + + TetrahedralInterpFloat(Input + 1, Tmp1, &p1); + + T = LutTable + K1; + p1.Table = T; + TetrahedralInterpFloat(Input + 1, Tmp2, &p1); + + for (i=0; i < p -> nOutputs; i++) + { + cmsFloat32Number y0 = Tmp1[i]; + cmsFloat32Number y1 = Tmp2[i]; + + Output[i] = y0 + (y1 - y0) * rest; + } +} + +#define EVAL_FNS(N,NM) static CMS_NO_SANITIZE \ +void Eval##N##Inputs(CMSREGISTER const cmsUInt16Number Input[], CMSREGISTER cmsUInt16Number Output[], CMSREGISTER const cmsInterpParams* p16)\ +{\ + const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;\ + cmsS15Fixed16Number fk;\ + cmsS15Fixed16Number k0, rk;\ + int K0, K1;\ + const cmsUInt16Number* T;\ + cmsUInt32Number i;\ + cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];\ + cmsInterpParams p1;\ +\ + fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);\ + k0 = FIXED_TO_INT(fk);\ + rk = FIXED_REST_TO_INT(fk);\ +\ + K0 = p16 -> opta[NM] * k0;\ + K1 = p16 -> opta[NM] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));\ +\ + p1 = *p16;\ + memmove(&p1.Domain[0], &p16 ->Domain[1], NM*sizeof(cmsUInt32Number));\ +\ + T = LutTable + K0;\ + p1.Table = T;\ +\ + Eval##NM##Inputs(Input + 1, Tmp1, &p1);\ +\ + T = LutTable + K1;\ + p1.Table = T;\ +\ + Eval##NM##Inputs(Input + 1, Tmp2, &p1);\ +\ + for (i=0; i < p16 -> nOutputs; i++) {\ +\ + Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);\ + }\ +}\ +\ +static void Eval##N##InputsFloat(const cmsFloat32Number Input[], \ + cmsFloat32Number Output[],\ + const cmsInterpParams * p)\ +{\ + const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;\ + cmsFloat32Number rest;\ + cmsFloat32Number pk;\ + int k0, K0, K1;\ + const cmsFloat32Number* T;\ + cmsUInt32Number i;\ + cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];\ + cmsInterpParams p1;\ +\ + pk = fclamp(Input[0]) * p->Domain[0];\ + k0 = _cmsQuickFloor(pk);\ + rest = pk - (cmsFloat32Number) k0;\ +\ + K0 = p -> opta[NM] * k0;\ + K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[NM]);\ +\ + p1 = *p;\ + memmove(&p1.Domain[0], &p ->Domain[1], NM*sizeof(cmsUInt32Number));\ +\ + T = LutTable + K0;\ + p1.Table = T;\ +\ + Eval##NM##InputsFloat(Input + 1, Tmp1, &p1);\ +\ + T = LutTable + K1;\ + p1.Table = T;\ +\ + Eval##NM##InputsFloat(Input + 1, Tmp2, &p1);\ +\ + for (i=0; i < p -> nOutputs; i++) {\ +\ + cmsFloat32Number y0 = Tmp1[i];\ + cmsFloat32Number y1 = Tmp2[i];\ +\ + Output[i] = y0 + (y1 - y0) * rest;\ + }\ +} + + +/** +* Thanks to Carles Llopis for the templating idea +*/ +EVAL_FNS(5, 4) +EVAL_FNS(6, 5) +EVAL_FNS(7, 6) +EVAL_FNS(8, 7) +EVAL_FNS(9, 8) +EVAL_FNS(10, 9) +EVAL_FNS(11, 10) +EVAL_FNS(12, 11) +EVAL_FNS(13, 12) +EVAL_FNS(14, 13) +EVAL_FNS(15, 14) + + +// The default factory +static +cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags) +{ + + cmsInterpFunction Interpolation; + cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT); + cmsBool IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR); + + memset(&Interpolation, 0, sizeof(Interpolation)); + + // Safety check + if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS) + return Interpolation; + + switch (nInputChannels) { + + case 1: // Gray LUT / linear + + if (nOutputChannels == 1) { + + if (IsFloat) + Interpolation.LerpFloat = LinLerp1Dfloat; + else + Interpolation.Lerp16 = LinLerp1D; + + } + else { + + if (IsFloat) + Interpolation.LerpFloat = Eval1InputFloat; + else + Interpolation.Lerp16 = Eval1Input; + } + break; + + case 2: // Duotone + if (IsFloat) + Interpolation.LerpFloat = BilinearInterpFloat; + else + Interpolation.Lerp16 = BilinearInterp16; + break; + + case 3: // RGB et al + + if (IsTrilinear) { + + if (IsFloat) + Interpolation.LerpFloat = TrilinearInterpFloat; + else + Interpolation.Lerp16 = TrilinearInterp16; + } + else { + + if (IsFloat) + Interpolation.LerpFloat = TetrahedralInterpFloat; + else { + + Interpolation.Lerp16 = TetrahedralInterp16; + } + } + break; + + case 4: // CMYK lut + + if (IsFloat) + Interpolation.LerpFloat = Eval4InputsFloat; + else + Interpolation.Lerp16 = Eval4Inputs; + break; + + case 5: // 5 Inks + if (IsFloat) + Interpolation.LerpFloat = Eval5InputsFloat; + else + Interpolation.Lerp16 = Eval5Inputs; + break; + + case 6: // 6 Inks + if (IsFloat) + Interpolation.LerpFloat = Eval6InputsFloat; + else + Interpolation.Lerp16 = Eval6Inputs; + break; + + case 7: // 7 inks + if (IsFloat) + Interpolation.LerpFloat = Eval7InputsFloat; + else + Interpolation.Lerp16 = Eval7Inputs; + break; + + case 8: // 8 inks + if (IsFloat) + Interpolation.LerpFloat = Eval8InputsFloat; + else + Interpolation.Lerp16 = Eval8Inputs; + break; + + case 9: + if (IsFloat) + Interpolation.LerpFloat = Eval9InputsFloat; + else + Interpolation.Lerp16 = Eval9Inputs; + break; + + case 10: + if (IsFloat) + Interpolation.LerpFloat = Eval10InputsFloat; + else + Interpolation.Lerp16 = Eval10Inputs; + break; + + case 11: + if (IsFloat) + Interpolation.LerpFloat = Eval11InputsFloat; + else + Interpolation.Lerp16 = Eval11Inputs; + break; + + case 12: + if (IsFloat) + Interpolation.LerpFloat = Eval12InputsFloat; + else + Interpolation.Lerp16 = Eval12Inputs; + break; + + case 13: + if (IsFloat) + Interpolation.LerpFloat = Eval13InputsFloat; + else + Interpolation.Lerp16 = Eval13Inputs; + break; + + case 14: + if (IsFloat) + Interpolation.LerpFloat = Eval14InputsFloat; + else + Interpolation.Lerp16 = Eval14Inputs; + break; + + case 15: + if (IsFloat) + Interpolation.LerpFloat = Eval15InputsFloat; + else + Interpolation.Lerp16 = Eval15Inputs; + break; + + default: + Interpolation.Lerp16 = NULL; + } + + return Interpolation; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsio0.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsio0.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsio0.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsio0.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1979 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Generic I/O, tag dictionary management, profile struct + +// IOhandlers are abstractions used by littleCMS to read from whatever file, stream, +// memory block or any storage. Each IOhandler provides implementations for read, +// write, seek and tell functions. LittleCMS code deals with IO across those objects. +// In this way, is easier to add support for new storage media. + +// NULL stream, for taking care of used space ------------------------------------- + +// NULL IOhandler basically does nothing but keep track on how many bytes have been +// written. This is handy when creating profiles, where the file size is needed in the +// header. Then, whole profile is serialized across NULL IOhandler and a second pass +// writes the bytes to the pertinent IOhandler. + +typedef struct { + cmsUInt32Number Pointer; // Points to current location +} FILENULL; + +static +cmsUInt32Number NULLRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + + cmsUInt32Number len = size * count; + ResData -> Pointer += len; + return count; + + cmsUNUSED_PARAMETER(Buffer); +} + +static +cmsBool NULLSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + + ResData ->Pointer = offset; + return TRUE; +} + +static +cmsUInt32Number NULLTell(cmsIOHANDLER* iohandler) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + return ResData -> Pointer; +} + +static +cmsBool NULLWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void *Ptr) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + + ResData ->Pointer += size; + if (ResData ->Pointer > iohandler->UsedSpace) + iohandler->UsedSpace = ResData ->Pointer; + + return TRUE; + + cmsUNUSED_PARAMETER(Ptr); +} + +static +cmsBool NULLClose(cmsIOHANDLER* iohandler) +{ + FILENULL* ResData = (FILENULL*) iohandler ->stream; + + _cmsFree(iohandler ->ContextID, ResData); + _cmsFree(iohandler ->ContextID, iohandler); + return TRUE; +} + +// The NULL IOhandler creator +cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) +{ + struct _cms_io_handler* iohandler = NULL; + FILENULL* fm = NULL; + + iohandler = (struct _cms_io_handler*) _cmsMallocZero(ContextID, sizeof(struct _cms_io_handler)); + if (iohandler == NULL) return NULL; + + fm = (FILENULL*) _cmsMallocZero(ContextID, sizeof(FILENULL)); + if (fm == NULL) goto Error; + + fm ->Pointer = 0; + + iohandler ->ContextID = ContextID; + iohandler ->stream = (void*) fm; + iohandler ->UsedSpace = 0; + iohandler ->ReportedSize = 0; + iohandler ->PhysicalFile[0] = 0; + + iohandler ->Read = NULLRead; + iohandler ->Seek = NULLSeek; + iohandler ->Close = NULLClose; + iohandler ->Tell = NULLTell; + iohandler ->Write = NULLWrite; + + return iohandler; + +Error: + if (iohandler) _cmsFree(ContextID, iohandler); + return NULL; + +} + + +// Memory-based stream -------------------------------------------------------------- + +// Those functions implements an iohandler which takes a block of memory as storage medium. + +typedef struct { + cmsUInt8Number* Block; // Points to allocated memory + cmsUInt32Number Size; // Size of allocated memory + cmsUInt32Number Pointer; // Points to current location + int FreeBlockOnClose; // As title + +} FILEMEM; + +static +cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + cmsUInt8Number* Ptr; + cmsUInt32Number len = size * count; + + if (ResData -> Pointer + len > ResData -> Size){ + + len = (ResData -> Size - ResData -> Pointer); + cmsSignalError(iohandler ->ContextID, cmsERROR_READ, "Read from memory error. Got %d bytes, block should be of %d bytes", len, count * size); + return 0; + } + + Ptr = ResData -> Block; + Ptr += ResData -> Pointer; + memmove(Buffer, Ptr, len); + ResData -> Pointer += len; + + return count; +} + +// SEEK_CUR is assumed +static +cmsBool MemorySeek(struct _cms_io_handler* iohandler, cmsUInt32Number offset) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + + if (offset > ResData ->Size) { + cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK, "Too few data; probably corrupted profile"); + return FALSE; + } + + ResData ->Pointer = offset; + return TRUE; +} + +// Tell for memory +static +cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + + if (ResData == NULL) return 0; + return ResData -> Pointer; +} + + +// Writes data to memory, also keeps used space for further reference. +static +cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + + if (ResData == NULL) return FALSE; // Housekeeping + + // Check for available space. Clip. + if (ResData->Pointer + size > ResData->Size) { + size = ResData ->Size - ResData->Pointer; + } + + if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing + + memmove(ResData ->Block + ResData ->Pointer, Ptr, size); + ResData ->Pointer += size; + + if (ResData ->Pointer > iohandler->UsedSpace) + iohandler->UsedSpace = ResData ->Pointer; + + return TRUE; +} + + +static +cmsBool MemoryClose(struct _cms_io_handler* iohandler) +{ + FILEMEM* ResData = (FILEMEM*) iohandler ->stream; + + if (ResData ->FreeBlockOnClose) { + + if (ResData ->Block) _cmsFree(iohandler ->ContextID, ResData ->Block); + } + + _cmsFree(iohandler ->ContextID, ResData); + _cmsFree(iohandler ->ContextID, iohandler); + + return TRUE; +} + +// Create a iohandler for memory block. AccessMode=='r' assumes the iohandler is going to read, and makes +// a copy of the memory block for letting user to free the memory after invoking open profile. In write +// mode ("w"), Buffer points to the begin of memory block to be written. +cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode) +{ + cmsIOHANDLER* iohandler = NULL; + FILEMEM* fm = NULL; + + _cmsAssert(AccessMode != NULL); + + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); + if (iohandler == NULL) return NULL; + + switch (*AccessMode) { + + case 'r': + fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM)); + if (fm == NULL) goto Error; + + if (Buffer == NULL) { + cmsSignalError(ContextID, cmsERROR_READ, "Couldn't read profile from NULL pointer"); + goto Error; + } + + fm ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, size); + if (fm ->Block == NULL) { + + _cmsFree(ContextID, fm); + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_READ, "Couldn't allocate %ld bytes for profile", (long) size); + return NULL; + } + + + memmove(fm->Block, Buffer, size); + fm ->FreeBlockOnClose = TRUE; + fm ->Size = size; + fm ->Pointer = 0; + iohandler -> ReportedSize = size; + break; + + case 'w': + fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM)); + if (fm == NULL) goto Error; + + fm ->Block = (cmsUInt8Number*) Buffer; + fm ->FreeBlockOnClose = FALSE; + fm ->Size = size; + fm ->Pointer = 0; + iohandler -> ReportedSize = 0; + break; + + default: + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown access mode '%c'", *AccessMode); + return NULL; + } + + iohandler ->ContextID = ContextID; + iohandler ->stream = (void*) fm; + iohandler ->UsedSpace = 0; + iohandler ->PhysicalFile[0] = 0; + + iohandler ->Read = MemoryRead; + iohandler ->Seek = MemorySeek; + iohandler ->Close = MemoryClose; + iohandler ->Tell = MemoryTell; + iohandler ->Write = MemoryWrite; + + return iohandler; + +Error: + if (fm) _cmsFree(ContextID, fm); + if (iohandler) _cmsFree(ContextID, iohandler); + return NULL; +} + +// File-based stream ------------------------------------------------------- + +// Read count elements of size bytes each. Return number of elements read +static +cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) +{ + cmsUInt32Number nReaded = (cmsUInt32Number) fread(Buffer, size, count, (FILE*) iohandler->stream); + + if (nReaded != count) { + cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size); + return 0; + } + + return nReaded; +} + +// Position file pointer in the file +static +cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) +{ + if (fseek((FILE*) iohandler ->stream, (long) offset, SEEK_SET) != 0) { + + cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Seek error; probably corrupted file"); + return FALSE; + } + + return TRUE; +} + +// Returns file pointer position or 0 on error, which is also a valid position. +static +cmsUInt32Number FileTell(cmsIOHANDLER* iohandler) +{ + long t = ftell((FILE*)iohandler ->stream); + if (t == -1L) { + cmsSignalError(iohandler->ContextID, cmsERROR_FILE, "Tell error; probably corrupted file"); + return 0; + } + + return (cmsUInt32Number)t; +} + +// Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error +static +cmsBool FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Buffer) +{ + if (size == 0) return TRUE; // We allow to write 0 bytes, but nothing is written + + iohandler->UsedSpace += size; + return (fwrite(Buffer, size, 1, (FILE*)iohandler->stream) == 1); +} + +// Closes the file +static +cmsBool FileClose(cmsIOHANDLER* iohandler) +{ + if (fclose((FILE*) iohandler ->stream) != 0) return FALSE; + _cmsFree(iohandler ->ContextID, iohandler); + return TRUE; +} + +// Create a iohandler for disk based files. +cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode) +{ + cmsIOHANDLER* iohandler = NULL; + FILE* fm = NULL; + cmsInt32Number fileLen; + + _cmsAssert(FileName != NULL); + _cmsAssert(AccessMode != NULL); + + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); + if (iohandler == NULL) return NULL; + + switch (*AccessMode) { + + case 'r': + fm = fopen(FileName, "rb"); + if (fm == NULL) { + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); + return NULL; + } + fileLen = cmsfilelength(fm); + if (fileLen < 0) + { + fclose(fm); + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of file '%s'", FileName); + return NULL; + } + + iohandler -> ReportedSize = (cmsUInt32Number) fileLen; + break; + + case 'w': + fm = fopen(FileName, "wb"); + if (fm == NULL) { + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName); + return NULL; + } + iohandler -> ReportedSize = 0; + break; + + default: + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode); + return NULL; + } + + iohandler ->ContextID = ContextID; + iohandler ->stream = (void*) fm; + iohandler ->UsedSpace = 0; + + // Keep track of the original file + strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); + iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; + + iohandler ->Read = FileRead; + iohandler ->Seek = FileSeek; + iohandler ->Close = FileClose; + iohandler ->Tell = FileTell; + iohandler ->Write = FileWrite; + + return iohandler; +} + +// Create a iohandler for stream based files +cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream) +{ + cmsIOHANDLER* iohandler = NULL; + cmsInt32Number fileSize; + + fileSize = cmsfilelength(Stream); + if (fileSize < 0) + { + cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of stream"); + return NULL; + } + + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); + if (iohandler == NULL) return NULL; + + iohandler -> ContextID = ContextID; + iohandler -> stream = (void*) Stream; + iohandler -> UsedSpace = 0; + iohandler -> ReportedSize = (cmsUInt32Number) fileSize; + iohandler -> PhysicalFile[0] = 0; + + iohandler ->Read = FileRead; + iohandler ->Seek = FileSeek; + iohandler ->Close = FileClose; + iohandler ->Tell = FileTell; + iohandler ->Write = FileWrite; + + return iohandler; +} + + + +// Close an open IO handler +cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io) +{ + return io -> Close(io); +} + +// ------------------------------------------------------------------------------------------------------- + +cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile; + + if (Icc == NULL) return NULL; + return Icc->IOhandler; +} + +// Creates an empty structure holding all required parameters +cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) +{ + time_t now = time(NULL); + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE)); + if (Icc == NULL) return NULL; + + Icc ->ContextID = ContextID; + + // Set it to empty + Icc -> TagCount = 0; + + // Set default version + Icc ->Version = 0x02100000; + + // Set creation date/time + memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); + + // Create a mutex if the user provided proper plugin. NULL otherwise + Icc ->UsrMutex = _cmsCreateMutex(ContextID); + + // Return the handle + return (cmsHPROFILE) Icc; +} + +cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + + if (Icc == NULL) return NULL; + return Icc -> ContextID; +} + + +// Return the number of tags +cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + if (Icc == NULL) return -1; + + return (cmsInt32Number) Icc->TagCount; +} + +// Return the tag signature of a given tag number +cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + + if (n > Icc->TagCount) return (cmsTagSignature) 0; // Mark as not available + if (n >= MAX_TABLE_TAG) return (cmsTagSignature) 0; // As double check + + return Icc ->TagNames[n]; +} + + +static +int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig) +{ + int i; + + for (i=0; i < (int) Profile -> TagCount; i++) { + + if (sig == Profile -> TagNames[i]) + return i; + } + + return -1; +} + +// Search for a specific tag in tag dictionary. Returns position or -1 if tag not found. +// If followlinks is turned on, then the position of the linked tag is returned +int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks) +{ + int n; + cmsTagSignature LinkedSig; + + do { + + // Search for given tag in ICC profile directory + n = SearchOneTag(Icc, sig); + if (n < 0) + return -1; // Not found + + if (!lFollowLinks) + return n; // Found, don't follow links + + // Is this a linked tag? + LinkedSig = Icc ->TagLinked[n]; + + // Yes, follow link + if (LinkedSig != (cmsTagSignature) 0) { + sig = LinkedSig; + } + + } while (LinkedSig != (cmsTagSignature) 0); + + return n; +} + +// Deletes a tag entry + +static +void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i) +{ + _cmsAssert(Icc != NULL); + _cmsAssert(i >= 0); + + + if (Icc -> TagPtrs[i] != NULL) { + + // Free previous version + if (Icc ->TagSaveAsRaw[i]) { + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + else { + cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler != NULL) { + + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); + Icc ->TagPtrs[i] = NULL; + } + } + + } +} + + +// Creates a new tag entry +static +cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) +{ + int i; + + // Search for the tag + i = _cmsSearchTag(Icc, sig, FALSE); + if (i >= 0) { + + // Already exists? delete it + _cmsDeleteTagByPos(Icc, i); + *NewPos = i; + } + else { + + // No, make a new one + if (Icc -> TagCount >= MAX_TABLE_TAG) { + cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); + return FALSE; + } + + *NewPos = (int) Icc ->TagCount; + Icc -> TagCount++; + } + + return TRUE; +} + + +// Check existence +cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) (void*) hProfile; + return _cmsSearchTag(Icc, sig, FALSE) >= 0; +} + +// Enforces that the profile version is per. spec. +// Operates on the big endian bytes from the profile. +// Called before converting to platform endianness. +// Byte 0 is BCD major version, so max 9. +// Byte 1 is 2 BCD digits, one per nibble. +// Reserved bytes 2 & 3 must be 0. +static +cmsUInt32Number _validatedVersion(cmsUInt32Number DWord) +{ + cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord; + cmsUInt8Number temp1; + cmsUInt8Number temp2; + + if (*pByte > 0x09) *pByte = (cmsUInt8Number) 0x09; + temp1 = (cmsUInt8Number) (*(pByte+1) & 0xf0); + temp2 = (cmsUInt8Number) (*(pByte+1) & 0x0f); + if (temp1 > 0x90U) temp1 = 0x90U; + if (temp2 > 0x09U) temp2 = 0x09U; + *(pByte+1) = (cmsUInt8Number)(temp1 | temp2); + *(pByte+2) = (cmsUInt8Number)0; + *(pByte+3) = (cmsUInt8Number)0; + + return DWord; +} + +// Read profile header and validate it +cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) +{ + cmsTagEntry Tag; + cmsICCHeader Header; + cmsUInt32Number i, j; + cmsUInt32Number HeaderSize; + cmsIOHANDLER* io = Icc ->IOhandler; + cmsUInt32Number TagCount; + + + // Read the header + if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) { + return FALSE; + } + + // Validate file as an ICC profile + if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) { + cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature"); + return FALSE; + } + + // Adjust endianness of the used parameters + Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); + Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); + Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); + + Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); + Icc -> flags = _cmsAdjustEndianess32(Header.flags); + Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); + Icc -> model = _cmsAdjustEndianess32(Header.model); + Icc -> creator = _cmsAdjustEndianess32(Header.creator); + + _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); + Icc -> Version = _cmsAdjustEndianess32(_validatedVersion(Header.version)); + + // Get size as reported in header + HeaderSize = _cmsAdjustEndianess32(Header.size); + + // Make sure HeaderSize is lower than profile size + if (HeaderSize >= Icc ->IOhandler ->ReportedSize) + HeaderSize = Icc ->IOhandler ->ReportedSize; + + + // Get creation date/time + _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created); + + // The profile ID are 32 raw bytes + memmove(Icc ->ProfileID.ID32, Header.profileID.ID32, 16); + + + // Read tag directory + if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE; + if (TagCount > MAX_TABLE_TAG) { + + cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", TagCount); + return FALSE; + } + + + // Read tag directory + Icc -> TagCount = 0; + for (i=0; i < TagCount; i++) { + + if (!_cmsReadUInt32Number(io, (cmsUInt32Number *) &Tag.sig)) return FALSE; + if (!_cmsReadUInt32Number(io, &Tag.offset)) return FALSE; + if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE; + + // Perform some sanity check. Offset + size should fall inside file. + if (Tag.offset + Tag.size > HeaderSize || + Tag.offset + Tag.size < Tag.offset) + continue; + + Icc -> TagNames[Icc ->TagCount] = Tag.sig; + Icc -> TagOffsets[Icc ->TagCount] = Tag.offset; + Icc -> TagSizes[Icc ->TagCount] = Tag.size; + + // Search for links + for (j=0; j < Icc ->TagCount; j++) { + + if ((Icc ->TagOffsets[j] == Tag.offset) && + (Icc ->TagSizes[j] == Tag.size)) { + + Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; + } + + } + + Icc ->TagCount++; + } + + return TRUE; +} + +// Saves profile header +cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) +{ + cmsICCHeader Header; + cmsUInt32Number i; + cmsTagEntry Tag; + cmsUInt32Number Count; + + Header.size = _cmsAdjustEndianess32(UsedSpace); + Header.cmmId = _cmsAdjustEndianess32(lcmsSignature); + Header.version = _cmsAdjustEndianess32(Icc ->Version); + + Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass); + Header.colorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> ColorSpace); + Header.pcs = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> PCS); + + // NOTE: in v4 Timestamp must be in UTC rather than in local time + _cmsEncodeDateTimeNumber(&Header.date, &Icc ->Created); + + Header.magic = _cmsAdjustEndianess32(cmsMagicNumber); + +#ifdef CMS_IS_WINDOWS_ + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); +#else + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); +#endif + + Header.flags = _cmsAdjustEndianess32(Icc -> flags); + Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); + Header.model = _cmsAdjustEndianess32(Icc -> model); + + _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes); + + // Rendering intent in the header (for embedded profiles) + Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent); + + // Illuminant is always D50 + Header.illuminant.X = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->X)); + Header.illuminant.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y)); + Header.illuminant.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z)); + + // Created by LittleCMS (that's me!) + Header.creator = _cmsAdjustEndianess32(lcmsSignature); + + memset(&Header.reserved, 0, sizeof(Header.reserved)); + + // Set profile ID. Endianness is always big endian + memmove(&Header.profileID, &Icc ->ProfileID, 16); + + // Dump the header + if (!Icc -> IOhandler->Write(Icc->IOhandler, sizeof(cmsICCHeader), &Header)) return FALSE; + + // Saves Tag directory + + // Get true count + Count = 0; + for (i=0; i < Icc -> TagCount; i++) { + if (Icc ->TagNames[i] != (cmsTagSignature) 0) + Count++; + } + + // Store number of tags + if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE; + + for (i=0; i < Icc -> TagCount; i++) { + + if (Icc ->TagNames[i] == (cmsTagSignature) 0) continue; // It is just a placeholder + + Tag.sig = (cmsTagSignature) _cmsAdjustEndianess32((cmsUInt32Number) Icc -> TagNames[i]); + Tag.offset = _cmsAdjustEndianess32((cmsUInt32Number) Icc -> TagOffsets[i]); + Tag.size = _cmsAdjustEndianess32((cmsUInt32Number) Icc -> TagSizes[i]); + + if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- Set/Get several struct members + + +cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> RenderingIntent; +} + +void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> RenderingIntent = RenderingIntent; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return (cmsUInt32Number) Icc -> flags; +} + +void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> flags = (cmsUInt32Number) Flags; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc ->manufacturer; +} + +void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> manufacturer = manufacturer; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc ->creator; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc ->model; +} + +void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> model = model; +} + +void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(Flags, &Icc -> attributes, sizeof(cmsUInt64Number)); +} + +void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(&Icc -> attributes, &Flags, sizeof(cmsUInt64Number)); +} + +void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(ProfileID, Icc ->ProfileID.ID8, 16); +} + +void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(&Icc -> ProfileID, ProfileID, 16); +} + +cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(Dest, &Icc ->Created, sizeof(struct tm)); + return TRUE; +} + +cmsColorSpaceSignature CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> PCS; +} + +void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> PCS = pcs; +} + +cmsColorSpaceSignature CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> ColorSpace; +} + +void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> ColorSpace = sig; +} + +cmsProfileClassSignature CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> DeviceClass; +} + +void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> DeviceClass = sig; +} + +cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc -> Version; +} + +void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + Icc -> Version = Version; +} + +// Get an hexadecimal number with same digits as v +static +cmsUInt32Number BaseToBase(cmsUInt32Number in, int BaseIn, int BaseOut) +{ + char Buff[100]; + int i, len; + cmsUInt32Number out; + + for (len=0; in > 0 && len < 100; len++) { + + Buff[len] = (char) (in % BaseIn); + in /= BaseIn; + } + + for (i=len-1, out=0; i >= 0; --i) { + out = out * BaseOut + Buff[i]; + } + + return out; +} + +void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + + // 4.2 -> 0x4200000 + + Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16; +} + +cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsUInt32Number n = Icc -> Version >> 16; + + return BaseToBase(n, 16, 10) / 100.0; +} +// -------------------------------------------------------------------------------------------------------------- + + +// Create profile from IOhandler +cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = io; + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + +// Create profile from IOhandler +cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = io; + if (write) { + + NewIcc -> IsWrite = TRUE; + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + + +// Create profile from disk file +cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = cmsOpenIOhandlerFromFile(ContextID, lpFileName, sAccess); + if (NewIcc ->IOhandler == NULL) goto Error; + + if (*sAccess == 'W' || *sAccess == 'w') { + + NewIcc -> IsWrite = TRUE; + + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + + +cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess) +{ + return cmsOpenProfileFromFileTHR(NULL, ICCProfile, sAccess); +} + + +cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char *sAccess) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = cmsOpenIOhandlerFromStream(ContextID, ICCProfile); + if (NewIcc ->IOhandler == NULL) goto Error; + + if (*sAccess == 'w') { + + NewIcc -> IsWrite = TRUE; + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; + +} + +cmsHPROFILE CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char *sAccess) +{ + return cmsOpenProfileFromStreamTHR(NULL, ICCProfile, sAccess); +} + + +// Open from memory block +cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void* MemPtr, cmsUInt32Number dwSize) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty; + + hEmpty = cmsCreateProfilePlaceholder(ContextID); + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + // Ok, in this case const void* is casted to void* just because open IO handler + // shares read and writing modes. Don't abuse this feature! + NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r"); + if (NewIcc ->IOhandler == NULL) goto Error; + + if (!_cmsReadHeader(NewIcc)) goto Error; + + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number dwSize) +{ + return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize); +} + + + +// Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig +static +cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) +{ + cmsUInt8Number* Data; + cmsUInt32Number i; + cmsUInt32Number Begin; + cmsIOHANDLER* io = Icc ->IOhandler; + cmsTagDescriptor* TagDescriptor; + cmsTagTypeSignature TypeBase; + cmsTagTypeSignature Type; + cmsTagTypeHandler* TypeHandler; + cmsFloat64Number Version = cmsGetProfileVersion((cmsHPROFILE) Icc); + cmsTagTypeHandler LocalTypeHandler; + + for (i=0; i < Icc -> TagCount; i++) { + + if (Icc ->TagNames[i] == (cmsTagSignature) 0) continue; + + // Linked tags are not written + if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue; + + Icc -> TagOffsets[i] = Begin = io ->UsedSpace; + + Data = (cmsUInt8Number*) Icc -> TagPtrs[i]; + + if (!Data) { + + // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. + // In this case a blind copy of the block data is performed + if (FileOrig != NULL && Icc -> TagOffsets[i]) { + + if (FileOrig->IOhandler != NULL) + { + cmsUInt32Number TagSize = FileOrig->TagSizes[i]; + cmsUInt32Number TagOffset = FileOrig->TagOffsets[i]; + void* Mem; + + if (!FileOrig->IOhandler->Seek(FileOrig->IOhandler, TagOffset)) return FALSE; + + Mem = _cmsMalloc(Icc->ContextID, TagSize); + if (Mem == NULL) return FALSE; + + if (FileOrig->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE; + if (!io->Write(io, TagSize, Mem)) return FALSE; + _cmsFree(Icc->ContextID, Mem); + + Icc->TagSizes[i] = (io->UsedSpace - Begin); + + + // Align to 32 bit boundary. + if (!_cmsWriteAlignment(io)) + return FALSE; + } + } + + continue; + } + + + // Should this tag be saved as RAW? If so, tagsizes should be specified in advance (no further cooking is done) + if (Icc ->TagSaveAsRaw[i]) { + + if (io -> Write(io, Icc ->TagSizes[i], Data) != 1) return FALSE; + } + else { + + // Search for support on this tag + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]); + if (TagDescriptor == NULL) continue; // Unsupported, ignore it + + if (TagDescriptor ->DecideType != NULL) { + + Type = TagDescriptor ->DecideType(Version, Data); + } + else { + + Type = TagDescriptor ->SupportedTypes[0]; + } + + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); + + if (TypeHandler == NULL) { + cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); + continue; + } + + TypeBase = TypeHandler ->Signature; + if (!_cmsWriteTypeBase(io, TypeBase)) + return FALSE; + + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, io, Data, TagDescriptor ->ElemCount)) { + + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) TypeBase); + cmsSignalError(Icc ->ContextID, cmsERROR_WRITE, "Couldn't write type '%s'", String); + return FALSE; + } + } + + + Icc -> TagSizes[i] = (io ->UsedSpace - Begin); + + // Align to 32 bit boundary. + if (! _cmsWriteAlignment(io)) + return FALSE; + } + + + return TRUE; +} + + +// Fill the offset and size fields for all linked tags +static +cmsBool SetLinks( _cmsICCPROFILE* Icc) +{ + cmsUInt32Number i; + + for (i=0; i < Icc -> TagCount; i++) { + + cmsTagSignature lnk = Icc ->TagLinked[i]; + if (lnk != (cmsTagSignature) 0) { + + int j = _cmsSearchTag(Icc, lnk, FALSE); + if (j >= 0) { + + Icc ->TagOffsets[i] = Icc ->TagOffsets[j]; + Icc ->TagSizes[i] = Icc ->TagSizes[j]; + } + + } + } + + return TRUE; +} + +// Low-level save to IOHANDLER. It returns the number of bytes used to +// store the profile, or zero on error. io may be NULL and in this case +// no data is written--only sizes are calculated +cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE Keep; + cmsIOHANDLER* PrevIO = NULL; + cmsUInt32Number UsedSpace; + cmsContext ContextID; + + _cmsAssert(hProfile != NULL); + + if (!_cmsLockMutex(Icc->ContextID, Icc->UsrMutex)) return 0; + memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); + + ContextID = cmsGetProfileContextID(hProfile); + PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID); + if (PrevIO == NULL) { + _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex); + return 0; + } + + // Pass #1 does compute offsets + + if (!_cmsWriteHeader(Icc, 0)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; + + UsedSpace = PrevIO ->UsedSpace; + + // Pass #2 does save to iohandler + + if (io != NULL) { + + Icc ->IOhandler = io; + if (!SetLinks(Icc)) goto Error; + if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; + } + + memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + if (!cmsCloseIOhandler(PrevIO)) + UsedSpace = 0; // As a error marker + + _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex); + + return UsedSpace; + + +Error: + cmsCloseIOhandler(PrevIO); + memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex); + + return 0; +} + + +// Low-level save to disk. +cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w"); + cmsBool rc; + + if (io == NULL) return FALSE; + + rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); + rc &= cmsCloseIOhandler(io); + + if (rc == FALSE) { // remove() is C99 per 7.19.4.1 + remove(FileName); // We have to IGNORE return value in this case + } + return rc; +} + +// Same as anterior, but for streams +cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream) +{ + cmsBool rc; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsIOHANDLER* io = cmsOpenIOhandlerFromStream(ContextID, Stream); + + if (io == NULL) return FALSE; + + rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); + rc &= cmsCloseIOhandler(io); + + return rc; +} + + +// Same as anterior, but for memory blocks. In this case, a NULL as MemPtr means calculate needed space only +cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded) +{ + cmsBool rc; + cmsIOHANDLER* io; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + _cmsAssert(BytesNeeded != NULL); + + // Should we just calculate the needed space? + if (MemPtr == NULL) { + + *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); + return (*BytesNeeded == 0) ? FALSE : TRUE; + } + + // That is a real write operation + io = cmsOpenIOhandlerFromMem(ContextID, MemPtr, *BytesNeeded, "w"); + if (io == NULL) return FALSE; + + rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); + rc &= cmsCloseIOhandler(io); + + return rc; +} + + + +// Closes a profile freeing any involved resources +cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsBool rc = TRUE; + cmsUInt32Number i; + + if (!Icc) return FALSE; + + // Was open in write mode? + if (Icc ->IsWrite) { + + Icc ->IsWrite = FALSE; // Assure no further writing + rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile); + } + + for (i=0; i < Icc -> TagCount; i++) { + + if (Icc -> TagPtrs[i]) { + + cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler != NULL) { + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; + + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); + } + else + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + } + + if (Icc ->IOhandler != NULL) { + rc &= cmsCloseIOhandler(Icc->IOhandler); + } + + _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex); + + _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory + + return rc; +} + + +// ------------------------------------------------------------------------------------------------------------------- + + +// Returns TRUE if a given tag is supported by a plug-in +static +cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Type) +{ + cmsUInt32Number i, nMaxTypes; + + nMaxTypes = TagDescriptor->nSupportedTypes; + if (nMaxTypes >= MAX_TYPES_IN_LCMS_PLUGIN) + nMaxTypes = MAX_TYPES_IN_LCMS_PLUGIN; + + for (i=0; i < nMaxTypes; i++) { + if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE; + } + + return FALSE; +} + + +// That's the main read function +void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsIOHANDLER* io; + cmsTagTypeHandler* TypeHandler; + cmsTagTypeHandler LocalTypeHandler; + cmsTagDescriptor* TagDescriptor; + cmsTagTypeSignature BaseType; + cmsUInt32Number Offset, TagSize; + cmsUInt32Number ElemCount; + int n; + + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; + + n = _cmsSearchTag(Icc, sig, TRUE); + if (n < 0) goto Error; // Not found, return NULL + + + // If the element is already in memory, return the pointer + if (Icc -> TagPtrs[n]) { + + if (Icc->TagTypeHandlers[n] == NULL) goto Error; + + // Sanity check + BaseType = Icc->TagTypeHandlers[n]->Signature; + if (BaseType == 0) goto Error; + + TagDescriptor = _cmsGetTagDescriptor(Icc->ContextID, sig); + if (TagDescriptor == NULL) goto Error; + + if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; + + if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return Icc -> TagPtrs[n]; + } + + // We need to read it. Get the offset and size to the file + Offset = Icc -> TagOffsets[n]; + TagSize = Icc -> TagSizes[n]; + + if (TagSize < 8) goto Error; + + io = Icc ->IOhandler; + // Seek to its location + if (!io -> Seek(io, Offset)) + goto Error; + + // Search for support on this tag + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + + // An unknown element was found. + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String); + goto Error; // Unsupported. + } + + // if supported, get type and check if in list + BaseType = _cmsReadTypeBase(io); + if (BaseType == 0) goto Error; + + if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; + + TagSize -= 8; // Already read by the type base logic + + // Get type handler + TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType); + if (TypeHandler == NULL) goto Error; + LocalTypeHandler = *TypeHandler; + + + // Read the tag + Icc -> TagTypeHandlers[n] = TypeHandler; + + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize); + + // The tag type is supported, but something wrong happened and we cannot read the tag. + // let know the user about this (although it is just a warning) + if (Icc -> TagPtrs[n] == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String); + goto Error; + } + + // This is a weird error that may be a symptom of something more serious, the number of + // stored item is actually less than the number of required elements. + if (ElemCount < TagDescriptor ->ElemCount) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", + String, TagDescriptor ->ElemCount, ElemCount); + goto Error; + } + + + // Return the data + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return Icc -> TagPtrs[n]; + + + // Return error and unlock tha data +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return NULL; +} + + +// Get true type of data +cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsTagTypeHandler* TypeHandler; + int n; + + // Search for given tag in ICC profile directory + n = _cmsSearchTag(Icc, sig, TRUE); + if (n < 0) return (cmsTagTypeSignature) 0; // Not found, return NULL + + // Get the handler. The true type is there + TypeHandler = Icc -> TagTypeHandlers[n]; + return TypeHandler ->Signature; +} + + +// Write a single tag. This just keeps track of the tak into a list of "to be written". If the tag is already +// in that list, the previous version is deleted. +cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsTagTypeHandler* TypeHandler = NULL; + cmsTagTypeHandler LocalTypeHandler; + cmsTagDescriptor* TagDescriptor = NULL; + cmsTagTypeSignature Type; + int i; + cmsFloat64Number Version; + char TypeString[5], SigString[5]; + + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + + // To delete tags. + if (data == NULL) { + + // Delete the tag + i = _cmsSearchTag(Icc, sig, FALSE); + if (i >= 0) { + + // Use zero as a mark of deleted + _cmsDeleteTagByPos(Icc, i); + Icc ->TagNames[i] = (cmsTagSignature) 0; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TRUE; + } + // Didn't find the tag + goto Error; + } + + if (!_cmsNewTag(Icc, sig, &i)) goto Error; + + // This is not raw + Icc ->TagSaveAsRaw[i] = FALSE; + + // This is not a link + Icc ->TagLinked[i] = (cmsTagSignature) 0; + + // Get information about the TAG. + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL){ + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig); + goto Error; + } + + + // Now we need to know which type to use. It depends on the version. + Version = cmsGetProfileVersion(hProfile); + + if (TagDescriptor ->DecideType != NULL) { + + // Let the tag descriptor to decide the type base on depending on + // the data. This is useful for example on parametric curves, where + // curves specified by a table cannot be saved as parametric and needs + // to be casted to single v2-curves, even on v4 profiles. + + Type = TagDescriptor ->DecideType(Version, data); + } + else { + + Type = TagDescriptor ->SupportedTypes[0]; + } + + // Does the tag support this type? + if (!IsTypeSupported(TagDescriptor, Type)) { + + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); + goto Error; + } + + // Does we have a handler for this type? + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); + if (TypeHandler == NULL) { + + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); + goto Error; // Should never happen + } + + + // Fill fields on icc structure + Icc ->TagTypeHandlers[i] = TypeHandler; + Icc ->TagNames[i] = sig; + Icc ->TagSizes[i] = 0; + Icc ->TagOffsets[i] = 0; + + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); + + if (Icc ->TagPtrs[i] == NULL) { + + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); + + goto Error; + } + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TRUE; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + +} + +// Read and write raw data. The only way those function would work and keep consistence with normal read and write +// is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained +// data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where +// raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows +// to write a tag as raw data and the read it as handled. + +cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + void *Object; + int i; + cmsIOHANDLER* MemIO; + cmsTagTypeHandler* TypeHandler = NULL; + cmsTagTypeHandler LocalTypeHandler; + cmsTagDescriptor* TagDescriptor = NULL; + cmsUInt32Number rc; + cmsUInt32Number Offset, TagSize; + + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + // Search for given tag in ICC profile directory + i = _cmsSearchTag(Icc, sig, TRUE); + if (i < 0) goto Error; // Not found, + + // It is already read? + if (Icc -> TagPtrs[i] == NULL) { + + // No yet, get original position + Offset = Icc ->TagOffsets[i]; + TagSize = Icc ->TagSizes[i]; + + // read the data directly, don't keep copy + if (data != NULL) { + + if (BufferSize < TagSize) + TagSize = BufferSize; + + if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; + if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TagSize; + } + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return Icc ->TagSizes[i]; + } + + // The data has been already read, or written. But wait!, maybe the user chose to save as + // raw data. In this case, return the raw data directly + if (Icc ->TagSaveAsRaw[i]) { + + if (data != NULL) { + + TagSize = Icc ->TagSizes[i]; + if (BufferSize < TagSize) + TagSize = BufferSize; + + memmove(data, Icc ->TagPtrs[i], TagSize); + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TagSize; + } + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return Icc ->TagSizes[i]; + } + + // Already read, or previously set by cmsWriteTag(). We need to serialize that + // data to raw in order to maintain consistency. + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + Object = cmsReadTag(hProfile, sig); + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (Object == NULL) goto Error; + + // Now we need to serialize to a memory block: just use a memory iohandler + + if (data == NULL) { + MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); + } else{ + MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); + } + if (MemIO == NULL) goto Error; + + // Obtain type handling for the tag + TypeHandler = Icc ->TagTypeHandlers[i]; + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + cmsCloseIOhandler(MemIO); + goto Error; + } + + if (TypeHandler == NULL) goto Error; + + // Serialize + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + + if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { + cmsCloseIOhandler(MemIO); + goto Error; + } + + if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { + cmsCloseIOhandler(MemIO); + goto Error; + } + + // Get Size and close + rc = MemIO ->Tell(MemIO); + cmsCloseIOhandler(MemIO); // Ignore return code this time + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return rc; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return 0; +} + +// Similar to the anterior. This function allows to write directly to the ICC profile any data, without +// checking anything. As a rule, mixing Raw with cooked doesn't work, so writing a tag as raw and then reading +// it as cooked without serializing does result into an error. If that is what you want, you will need to dump +// the profile to memry or disk and then reopen it. +cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + int i; + + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } + + // Mark the tag as being written as RAW + Icc ->TagSaveAsRaw[i] = TRUE; + Icc ->TagNames[i] = sig; + Icc ->TagLinked[i] = (cmsTagSignature) 0; + + // Keep a copy of the block + Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size); + Icc ->TagSizes[i] = Size; + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + + if (Icc->TagPtrs[i] == NULL) { + Icc->TagNames[i] = (cmsTagSignature) 0; + return FALSE; + } + return TRUE; +} + +// Using this function you can collapse several tag entries to the same block in the profile +cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + int i; + + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } + + // Keep necessary information + Icc ->TagSaveAsRaw[i] = FALSE; + Icc ->TagNames[i] = sig; + Icc ->TagLinked[i] = dest; + + Icc ->TagPtrs[i] = NULL; + Icc ->TagSizes[i] = 0; + Icc ->TagOffsets[i] = 0; + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TRUE; +} + + +// Returns the tag linked to sig, in the case two tags are sharing same resource +cmsTagSignature CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + int i; + + // Search for given tag in ICC profile directory + i = _cmsSearchTag(Icc, sig, FALSE); + if (i < 0) return (cmsTagSignature) 0; // Not found, return 0 + + return Icc -> TagLinked[i]; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsio1.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsio1.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsio1.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsio1.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1057 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Read tags using low-level functions, provides necessary glue code to adapt versions, etc. + +// LUT tags +static const cmsTagSignature Device2PCS16[] = {cmsSigAToB0Tag, // Perceptual + cmsSigAToB1Tag, // Relative colorimetric + cmsSigAToB2Tag, // Saturation + cmsSigAToB1Tag }; // Absolute colorimetric + +static const cmsTagSignature Device2PCSFloat[] = {cmsSigDToB0Tag, // Perceptual + cmsSigDToB1Tag, // Relative colorimetric + cmsSigDToB2Tag, // Saturation + cmsSigDToB3Tag }; // Absolute colorimetric + +static const cmsTagSignature PCS2Device16[] = {cmsSigBToA0Tag, // Perceptual + cmsSigBToA1Tag, // Relative colorimetric + cmsSigBToA2Tag, // Saturation + cmsSigBToA1Tag }; // Absolute colorimetric + +static const cmsTagSignature PCS2DeviceFloat[] = {cmsSigBToD0Tag, // Perceptual + cmsSigBToD1Tag, // Relative colorimetric + cmsSigBToD2Tag, // Saturation + cmsSigBToD3Tag }; // Absolute colorimetric + + +// Factors to convert from 1.15 fixed point to 0..1.0 range and vice-versa +#define InpAdj (1.0/MAX_ENCODEABLE_XYZ) // (65536.0/(65535.0*2.0)) +#define OutpAdj (MAX_ENCODEABLE_XYZ) // ((2.0*65535.0)/65536.0) + +// Several resources for gray conversions. +static const cmsFloat64Number GrayInputMatrix[] = { (InpAdj*cmsD50X), (InpAdj*cmsD50Y), (InpAdj*cmsD50Z) }; +static const cmsFloat64Number OneToThreeInputMatrix[] = { 1, 1, 1 }; +static const cmsFloat64Number PickYMatrix[] = { 0, (OutpAdj*cmsD50Y), 0 }; +static const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 }; + +// Get a media white point fixing some issues found in certain old profiles +cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile) +{ + cmsCIEXYZ* Tag; + + _cmsAssert(Dest != NULL); + + Tag = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); + + // If no wp, take D50 + if (Tag == NULL) { + *Dest = *cmsD50_XYZ(); + return TRUE; + } + + // V2 display profiles should give D50 + if (cmsGetEncodedICCversion(hProfile) < 0x4000000) { + + if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) { + *Dest = *cmsD50_XYZ(); + return TRUE; + } + } + + // All seems ok + *Dest = *Tag; + return TRUE; +} + + +// Chromatic adaptation matrix. Fix some issues as well +cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) +{ + cmsMAT3* Tag; + + _cmsAssert(Dest != NULL); + + Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag); + + if (Tag != NULL) { + *Dest = *Tag; + return TRUE; + } + + // No CHAD available, default it to identity + _cmsMAT3identity(Dest); + + // V2 display profiles should give D50 + if (cmsGetEncodedICCversion(hProfile) < 0x4000000) { + + if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) { + + cmsCIEXYZ* White = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag); + + if (White == NULL) { + + _cmsMAT3identity(Dest); + return TRUE; + } + + return _cmsAdaptationMatrix(Dest, NULL, White, cmsD50_XYZ()); + } + } + + return TRUE; +} + + +// Auxiliary, read colorants as a MAT3 structure. Used by any function that needs a matrix-shaper +static +cmsBool ReadICCMatrixRGB2XYZ(cmsMAT3* r, cmsHPROFILE hProfile) +{ + cmsCIEXYZ *PtrRed, *PtrGreen, *PtrBlue; + + _cmsAssert(r != NULL); + + PtrRed = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigRedColorantTag); + PtrGreen = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigGreenColorantTag); + PtrBlue = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigBlueColorantTag); + + if (PtrRed == NULL || PtrGreen == NULL || PtrBlue == NULL) + return FALSE; + + _cmsVEC3init(&r -> v[0], PtrRed -> X, PtrGreen -> X, PtrBlue -> X); + _cmsVEC3init(&r -> v[1], PtrRed -> Y, PtrGreen -> Y, PtrBlue -> Y); + _cmsVEC3init(&r -> v[2], PtrRed -> Z, PtrGreen -> Z, PtrBlue -> Z); + + return TRUE; +} + + +// Gray input pipeline +static +cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) +{ + cmsToneCurve *GrayTRC; + cmsPipeline* Lut; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); + if (GrayTRC == NULL) return NULL; + + Lut = cmsPipelineAlloc(ContextID, 1, 3); + if (Lut == NULL) + goto Error; + + if (cmsGetPCS(hProfile) == cmsSigLabData) { + + // In this case we implement the profile as an identity matrix plus 3 tone curves + cmsUInt16Number Zero[2] = { 0x8080, 0x8080 }; + cmsToneCurve* EmptyTab; + cmsToneCurve* LabCurves[3]; + + EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); + + if (EmptyTab == NULL) + goto Error; + + LabCurves[0] = GrayTRC; + LabCurves[1] = EmptyTab; + LabCurves[2] = EmptyTab; + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves))) { + cmsFreeToneCurve(EmptyTab); + goto Error; + } + + cmsFreeToneCurve(EmptyTab); + + } + else { + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL))) + goto Error; + } + + return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; +} + +// RGB Matrix shaper +static +cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile) +{ + cmsPipeline* Lut; + cmsMAT3 Mat; + cmsToneCurve *Shapes[3]; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + int i, j; + + if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) return NULL; + + // XYZ PCS in encoded in 1.15 format, and the matrix output comes in 0..0xffff range, so + // we need to adjust the output by a factor of (0x10000/0xffff) to put data in + // a 1.16 range, and then a >> 1 to obtain 1.15. The total factor is (65536.0)/(65535.0*2) + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + Mat.v[i].n[j] *= InpAdj; + + + Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); + Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag); + Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag); + + if (!Shapes[0] || !Shapes[1] || !Shapes[2]) + return NULL; + + Lut = cmsPipelineAlloc(ContextID, 3, 3); + if (Lut != NULL) { + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL))) + goto Error; + + // Note that it is certainly possible a single profile would have a LUT based + // tag for output working in lab and a matrix-shaper for the fallback cases. + // This is not allowed by the spec, but this code is tolerant to those cases + if (cmsGetPCS(hProfile) == cmsSigLabData) { + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID))) + goto Error; + } + + } + + return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; +} + + + +// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded +static +cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile); + cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); + + if (Lut == NULL) return NULL; + + // input and output of transform are in lcms 0..1 encoding. If XYZ or Lab spaces are used, + // these need to be normalized into the appropriate ranges (Lab = 100,0,0, XYZ=1.0,1.0,1.0) + if ( spc == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; + } + else if (spc == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; + } + + if ( PCS == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; + } + else if( PCS == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; + } + + return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; +} + + +// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc +// is adjusted here in order to create a LUT that takes care of all those details. +// We add intent = 0xffffffff as a way to read matrix shaper always, no matter of other LUT +cmsPipeline* CMSEXPORT _cmsReadInputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent) +{ + cmsTagTypeSignature OriginalType; + cmsTagSignature tag16; + cmsTagSignature tagFloat; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + // On named color, take the appropriate tag + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + + cmsPipeline* Lut; + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag); + + if (nc == NULL) return NULL; + + Lut = cmsPipelineAlloc(ContextID, 0, 0); + if (Lut == NULL) { + cmsFreeNamedColorList(nc); + return NULL; + } + + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) { + cmsPipelineFree(Lut); + return NULL; + } + return Lut; + } + + // This is an attempt to reuse this function to retrieve the matrix-shaper as pipeline no + // matter other LUT are present and have precedence. Intent = 0xffffffff can be used for that. + if (Intent <= INTENT_ABSOLUTE_COLORIMETRIC) { + + tag16 = Device2PCS16[Intent]; + tagFloat = Device2PCSFloat[Intent]; + + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V4, but the encoding range is no + // longer 0..1.0, so we need to add an stage depending on the color space + return _cmsReadFloatInputTag(hProfile, tagFloat); + } + + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = Device2PCS16[0]; + } + + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + + // Check profile version and LUT type. Do the necessary adjustments if needed + + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; + + // After reading it, we have now info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + + // We need to adjust data only for Lab16 on output + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; + + // If the input is Lab, add also a conversion at the begin + if (cmsGetColorSpace(hProfile) == cmsSigLabData && + !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; + + // Add a matrix for conversion V2 to V4 Lab PCS + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + + return Lut; +Error: + cmsPipelineFree(Lut); + return NULL; + } + } + + // Lut was not found, try to create a matrix-shaper + + // Check if this is a grayscale profile. + if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { + + // if so, build appropriate conversion tables. + // The tables are the PCS iluminant, scaled across GrayTRC + return BuildGrayInputMatrixPipeline(hProfile); + } + + // Not gray, create a normal matrix-shaper + return BuildRGBInputMatrixShaper(hProfile); +} + +// --------------------------------------------------------------------------------------------------------------- + +// Gray output pipeline. +// XYZ -> Gray or Lab -> Gray. Since we only know the GrayTRC, we need to do some assumptions. Gray component will be +// given by Y on XYZ PCS and by L* on Lab PCS, Both across inverse TRC curve. +// The complete pipeline on XYZ is Matrix[3:1] -> Tone curve and in Lab Matrix[3:1] -> Tone Curve as well. + +static +cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile) +{ + cmsToneCurve *GrayTRC, *RevGrayTRC; + cmsPipeline* Lut; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag); + if (GrayTRC == NULL) return NULL; + + RevGrayTRC = cmsReverseToneCurve(GrayTRC); + if (RevGrayTRC == NULL) return NULL; + + Lut = cmsPipelineAlloc(ContextID, 3, 1); + if (Lut == NULL) { + cmsFreeToneCurve(RevGrayTRC); + return NULL; + } + + if (cmsGetPCS(hProfile) == cmsSigLabData) { + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL))) + goto Error; + } + else { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL))) + goto Error; + } + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC))) + goto Error; + + cmsFreeToneCurve(RevGrayTRC); + return Lut; + +Error: + cmsFreeToneCurve(RevGrayTRC); + cmsPipelineFree(Lut); + return NULL; +} + + +static +cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) +{ + cmsPipeline* Lut; + cmsToneCurve *Shapes[3], *InvShapes[3]; + cmsMAT3 Mat, Inv; + int i, j; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) + return NULL; + + if (!_cmsMAT3inverse(&Mat, &Inv)) + return NULL; + + // XYZ PCS in encoded in 1.15 format, and the matrix input should come in 0..0xffff range, so + // we need to adjust the input by a << 1 to obtain a 1.16 fixed and then by a factor of + // (0xffff/0x10000) to put data in 0..0xffff range. Total factor is (2.0*65535.0)/65536.0; + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + Inv.v[i].n[j] *= OutpAdj; + + Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag); + Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag); + Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag); + + if (!Shapes[0] || !Shapes[1] || !Shapes[2]) + return NULL; + + InvShapes[0] = cmsReverseToneCurve(Shapes[0]); + InvShapes[1] = cmsReverseToneCurve(Shapes[1]); + InvShapes[2] = cmsReverseToneCurve(Shapes[2]); + + if (!InvShapes[0] || !InvShapes[1] || !InvShapes[2]) { + return NULL; + } + + Lut = cmsPipelineAlloc(ContextID, 3, 3); + if (Lut != NULL) { + + // Note that it is certainly possible a single profile would have a LUT based + // tag for output working in lab and a matrix-shaper for the fallback cases. + // This is not allowed by the spec, but this code is tolerant to those cases + if (cmsGetPCS(hProfile) == cmsSigLabData) { + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID))) + goto Error; + } + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes))) + goto Error; + } + + cmsFreeToneCurveTriple(InvShapes); + return Lut; +Error: + cmsFreeToneCurveTriple(InvShapes); + cmsPipelineFree(Lut); + return NULL; +} + + +// Change CLUT interpolation to trilinear +static +void ChangeInterpolationToTrilinear(cmsPipeline* Lut) +{ + cmsStage* Stage; + + for (Stage = cmsPipelineGetPtrToFirstStage(Lut); + Stage != NULL; + Stage = cmsStageNext(Stage)) { + + if (cmsStageType(Stage) == cmsSigCLutElemType) { + + _cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data; + + CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR; + _cmsSetInterpolationRoutine(Lut->ContextID, CLUT ->Params); + } + } +} + + +// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded +static +cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); + cmsColorSpaceSignature dataSpace = cmsGetColorSpace(hProfile); + + if (Lut == NULL) return NULL; + + // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding, + // and since the formatter has already accommodated to 0..1.0, we should undo this change + if ( PCS == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; + } + else + if (PCS == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; + } + + // the output can be Lab or XYZ, in which case normalisation is needed on the end of the pipeline + if ( dataSpace == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; + } + else if (dataSpace == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; + } + + return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; +} + +// Create an output MPE LUT from agiven profile. Version mismatches are handled here +cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent) +{ + cmsTagTypeSignature OriginalType; + cmsTagSignature tag16; + cmsTagSignature tagFloat; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + + if (Intent <= INTENT_ABSOLUTE_COLORIMETRIC) { + + tag16 = PCS2Device16[Intent]; + tagFloat = PCS2DeviceFloat[Intent]; + + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V4 + return _cmsReadFloatOutputTag(hProfile, tagFloat); + } + + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = PCS2Device16[0]; + } + + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + + // Check profile version and LUT type. Do the necessary adjustments if needed + + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; + + // After reading it, we have info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + if (Lut == NULL) return NULL; + + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used + if (cmsGetPCS(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); + + // We need to adjust data only for Lab and Lut16 type + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; + + // Add a matrix for conversion V4 to V2 Lab PCS + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; + + // If the output is Lab, add also a conversion at the end + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + + return Lut; +Error: + cmsPipelineFree(Lut); + return NULL; + } + } + + // Lut not found, try to create a matrix-shaper + + // Check if this is a grayscale profile. + if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { + + // if so, build appropriate conversion tables. + // The tables are the PCS iluminant, scaled across GrayTRC + return BuildGrayOutputPipeline(hProfile); + } + + // Not gray, create a normal matrix-shaper, which only operates in XYZ space + return BuildRGBOutputMatrixShaper(hProfile); +} + +// --------------------------------------------------------------------------------------------------------------- + +// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if neded +static +cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*)cmsReadTag(hProfile, tagFloat)); + cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); + cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile); + + if (Lut == NULL) return NULL; + + if (spc == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; + } + else + if (spc == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; + } + + if (PCS == cmsSigLabData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; + } + else + if (PCS == cmsSigXYZData) + { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; + } + + return Lut; +Error: + cmsPipelineFree(Lut); + return NULL; +} + +// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The +// tag name here may default to AToB0 +cmsPipeline* CMSEXPORT _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent) +{ + cmsPipeline* Lut; + cmsTagTypeSignature OriginalType; + cmsTagSignature tag16; + cmsTagSignature tagFloat; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + + if (Intent > INTENT_ABSOLUTE_COLORIMETRIC) + return NULL; + + tag16 = Device2PCS16[Intent]; + tagFloat = Device2PCSFloat[Intent]; + + // On named color, take the appropriate tag + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*)cmsReadTag(hProfile, cmsSigNamedColor2Tag); + + if (nc == NULL) return NULL; + + Lut = cmsPipelineAlloc(ContextID, 0, 0); + if (Lut == NULL) + goto Error; + + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE))) + goto Error; + + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + + return Lut; + Error: + cmsPipelineFree(Lut); + cmsFreeNamedColorList(nc); + return NULL; + } + + + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V + return _cmsReadFloatDevicelinkTag(hProfile, tagFloat); + } + + tagFloat = Device2PCSFloat[0]; + if (cmsIsTag(hProfile, tagFloat)) { + + return cmsPipelineDup((cmsPipeline*)cmsReadTag(hProfile, tagFloat)); + } + + if (!cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + + tag16 = Device2PCS16[0]; + if (!cmsIsTag(hProfile, tag16)) return NULL; + } + + // Check profile version and LUT type. Do the necessary adjustments if needed + + // Read the tag + Lut = (cmsPipeline*)cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; + + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + if (Lut == NULL) return NULL; + + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used + if (cmsGetPCS(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); + + // After reading it, we have info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); + + // We need to adjust data for Lab16 on output + if (OriginalType != cmsSigLut16Type) return Lut; + + // Here it is possible to get Lab on both sides + + if (cmsGetColorSpace(hProfile) == cmsSigLabData) { + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error2; + } + + if (cmsGetPCS(hProfile) == cmsSigLabData) { + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error2; + } + + return Lut; + +Error2: + cmsPipelineFree(Lut); + return NULL; +} + +// --------------------------------------------------------------------------------------------------------------- + +// Returns TRUE if the profile is implemented as matrix-shaper +cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile) +{ + switch (cmsGetColorSpace(hProfile)) { + + case cmsSigGrayData: + + return cmsIsTag(hProfile, cmsSigGrayTRCTag); + + case cmsSigRgbData: + + return (cmsIsTag(hProfile, cmsSigRedColorantTag) && + cmsIsTag(hProfile, cmsSigGreenColorantTag) && + cmsIsTag(hProfile, cmsSigBlueColorantTag) && + cmsIsTag(hProfile, cmsSigRedTRCTag) && + cmsIsTag(hProfile, cmsSigGreenTRCTag) && + cmsIsTag(hProfile, cmsSigBlueTRCTag)); + + default: + + return FALSE; + } +} + +// Returns TRUE if the intent is implemented as CLUT +cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection) +{ + const cmsTagSignature* TagTable; + + // For devicelinks, the supported intent is that one stated in the header + if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) { + return (cmsGetHeaderRenderingIntent(hProfile) == Intent); + } + + switch (UsedDirection) { + + case LCMS_USED_AS_INPUT: TagTable = Device2PCS16; break; + case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device16; break; + + // For proofing, we need rel. colorimetric in output. Let's do some recursion + case LCMS_USED_AS_PROOF: + return cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) && + cmsIsIntentSupported(hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_OUTPUT); + + default: + cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_RANGE, "Unexpected direction (%d)", UsedDirection); + return FALSE; + } + + return cmsIsTag(hProfile, TagTable[Intent]); + +} + + +// Return info about supported intents +cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, + cmsUInt32Number Intent, cmsUInt32Number UsedDirection) +{ + + if (cmsIsCLUT(hProfile, Intent, UsedDirection)) return TRUE; + + // Is there any matrix-shaper? If so, the intent is supported. This is a bit odd, since V2 matrix shaper + // does not fully support relative colorimetric because they cannot deal with non-zero black points, but + // many profiles claims that, and this is certainly not true for V4 profiles. Lets answer "yes" no matter + // the accuracy would be less than optimal in rel.col and v2 case. + + return cmsIsMatrixShaper(hProfile); +} + + +// --------------------------------------------------------------------------------------------------------------- + +// Read both, profile sequence description and profile sequence id if present. Then combine both to +// create qa unique structure holding both. Shame on ICC to store things in such complicated way. +cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile) +{ + cmsSEQ* ProfileSeq; + cmsSEQ* ProfileId; + cmsSEQ* NewSeq; + cmsUInt32Number i; + + // Take profile sequence description first + ProfileSeq = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceDescTag); + + // Take profile sequence ID + ProfileId = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceIdTag); + + if (ProfileSeq == NULL && ProfileId == NULL) return NULL; + + if (ProfileSeq == NULL) return cmsDupProfileSequenceDescription(ProfileId); + if (ProfileId == NULL) return cmsDupProfileSequenceDescription(ProfileSeq); + + // We have to mix both together. For that they must agree + if (ProfileSeq ->n != ProfileId ->n) return cmsDupProfileSequenceDescription(ProfileSeq); + + NewSeq = cmsDupProfileSequenceDescription(ProfileSeq); + + // Ok, proceed to the mixing + if (NewSeq != NULL) { + for (i=0; i < ProfileSeq ->n; i++) { + + memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID)); + NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description); + } + } + return NewSeq; +} + +// Dump the contents of profile sequence in both tags (if v4 available) +cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq) +{ + if (!cmsWriteTag(hProfile, cmsSigProfileSequenceDescTag, seq)) return FALSE; + + if (cmsGetEncodedICCversion(hProfile) >= 0x4000000) { + + if (!cmsWriteTag(hProfile, cmsSigProfileSequenceIdTag, seq)) return FALSE; + } + + return TRUE; +} + + +// Auxiliary, read and duplicate a MLU if found. +static +cmsMLU* GetMLUFromProfile(cmsHPROFILE h, cmsTagSignature sig) +{ + cmsMLU* mlu = (cmsMLU*) cmsReadTag(h, sig); + if (mlu == NULL) return NULL; + + return cmsMLUdup(mlu); +} + +// Create a sequence description out of an array of profiles +cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]) +{ + cmsUInt32Number i; + cmsSEQ* seq = cmsAllocProfileSequenceDescription(ContextID, nProfiles); + + if (seq == NULL) return NULL; + + for (i=0; i < nProfiles; i++) { + + cmsPSEQDESC* ps = &seq ->seq[i]; + cmsHPROFILE h = hProfiles[i]; + cmsTechnologySignature* techpt; + + cmsGetHeaderAttributes(h, &ps ->attributes); + cmsGetHeaderProfileID(h, ps ->ProfileID.ID8); + ps ->deviceMfg = cmsGetHeaderManufacturer(h); + ps ->deviceModel = cmsGetHeaderModel(h); + + techpt = (cmsTechnologySignature*) cmsReadTag(h, cmsSigTechnologyTag); + if (techpt == NULL) + ps ->technology = (cmsTechnologySignature) 0; + else + ps ->technology = *techpt; + + ps ->Manufacturer = GetMLUFromProfile(h, cmsSigDeviceMfgDescTag); + ps ->Model = GetMLUFromProfile(h, cmsSigDeviceModelDescTag); + ps ->Description = GetMLUFromProfile(h, cmsSigProfileDescriptionTag); + + } + + return seq; +} + +// ------------------------------------------------------------------------------------------------------------------- + + +static +const cmsMLU* GetInfo(cmsHPROFILE hProfile, cmsInfoType Info) +{ + cmsTagSignature sig; + + switch (Info) { + + case cmsInfoDescription: + sig = cmsSigProfileDescriptionTag; + break; + + case cmsInfoManufacturer: + sig = cmsSigDeviceMfgDescTag; + break; + + case cmsInfoModel: + sig = cmsSigDeviceModelDescTag; + break; + + case cmsInfoCopyright: + sig = cmsSigCopyrightTag; + break; + + default: return NULL; + } + + + return (cmsMLU*) cmsReadTag(hProfile, sig); +} + + + +cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize) +{ + const cmsMLU* mlu = GetInfo(hProfile, Info); + if (mlu == NULL) return 0; + + return cmsMLUgetWide(mlu, LanguageCode, CountryCode, Buffer, BufferSize); +} + + +cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) +{ + const cmsMLU* mlu = GetInfo(hProfile, Info); + if (mlu == NULL) return 0; + + return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize); +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmslut.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmslut.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmslut.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmslut.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1866 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// Allocates an empty multi profile element +cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, + cmsStageSignature Type, + cmsUInt32Number InputChannels, + cmsUInt32Number OutputChannels, + _cmsStageEvalFn EvalPtr, + _cmsStageDupElemFn DupElemPtr, + _cmsStageFreeElemFn FreePtr, + void* Data) +{ + cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage)); + + if (ph == NULL) return NULL; + + + ph ->ContextID = ContextID; + + ph ->Type = Type; + ph ->Implements = Type; // By default, no clue on what is implementing + + ph ->InputChannels = InputChannels; + ph ->OutputChannels = OutputChannels; + ph ->EvalPtr = EvalPtr; + ph ->DupElemPtr = DupElemPtr; + ph ->FreePtr = FreePtr; + ph ->Data = Data; + + return ph; +} + + +static +void EvaluateIdentity(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number)); +} + + +cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels) +{ + return _cmsStageAllocPlaceholder(ContextID, + cmsSigIdentityElemType, + nChannels, nChannels, + EvaluateIdentity, + NULL, + NULL, + NULL); + } + +// Conversion functions. From floating point to 16 bits +static +void FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32Number n) +{ + cmsUInt32Number i; + + for (i=0; i < n; i++) { + Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); + } +} + +// From 16 bits to floating point +static +void From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32Number n) +{ + cmsUInt32Number i; + + for (i=0; i < n; i++) { + Out[i] = (cmsFloat32Number) In[i] / 65535.0F; + } +} + + +// This function is quite useful to analyze the structure of a LUT and retrieve the MPE elements +// that conform the LUT. It should be called with the LUT, the number of expected elements and +// then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If +// the function founds a match with current pipeline, it fills the pointers and returns TRUE +// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass +// the storage process. +cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...) +{ + va_list args; + cmsUInt32Number i; + cmsStage* mpe; + cmsStageSignature Type; + void** ElemPtr; + + // Make sure same number of elements + if (cmsPipelineStageCount(Lut) != n) return FALSE; + + va_start(args, n); + + // Iterate across asked types + mpe = Lut ->Elements; + for (i=0; i < n; i++) { + + // Get asked type. cmsStageSignature is promoted to int by compiler + Type = (cmsStageSignature)va_arg(args, int); + if (mpe ->Type != Type) { + + va_end(args); // Mismatch. We are done. + return FALSE; + } + mpe = mpe ->Next; + } + + // Found a combination, fill pointers if not NULL + mpe = Lut ->Elements; + for (i=0; i < n; i++) { + + ElemPtr = va_arg(args, void**); + if (ElemPtr != NULL) + *ElemPtr = mpe; + + mpe = mpe ->Next; + } + + va_end(args); + return TRUE; +} + +// Below there are implementations for several types of elements. Each type may be implemented by a +// evaluation function, a duplication function, a function to free resources and a constructor. + +// ************************************************************************************************* +// Type cmsSigCurveSetElemType (curves) +// ************************************************************************************************* + +cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe) +{ + _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; + + return Data ->TheCurves; +} + +static +void EvaluateCurves(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + _cmsStageToneCurvesData* Data; + cmsUInt32Number i; + + _cmsAssert(mpe != NULL); + + Data = (_cmsStageToneCurvesData*) mpe ->Data; + if (Data == NULL) return; + + if (Data ->TheCurves == NULL) return; + + for (i=0; i < Data ->nCurves; i++) { + Out[i] = cmsEvalToneCurveFloat(Data ->TheCurves[i], In[i]); + } +} + +static +void CurveSetElemTypeFree(cmsStage* mpe) +{ + _cmsStageToneCurvesData* Data; + cmsUInt32Number i; + + _cmsAssert(mpe != NULL); + + Data = (_cmsStageToneCurvesData*) mpe ->Data; + if (Data == NULL) return; + + if (Data ->TheCurves != NULL) { + for (i=0; i < Data ->nCurves; i++) { + if (Data ->TheCurves[i] != NULL) + cmsFreeToneCurve(Data ->TheCurves[i]); + } + } + _cmsFree(mpe ->ContextID, Data ->TheCurves); + _cmsFree(mpe ->ContextID, Data); +} + + +static +void* CurveSetDup(cmsStage* mpe) +{ + _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; + _cmsStageToneCurvesData* NewElem; + cmsUInt32Number i; + + NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageToneCurvesData)); + if (NewElem == NULL) return NULL; + + NewElem ->nCurves = Data ->nCurves; + NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(mpe ->ContextID, NewElem ->nCurves, sizeof(cmsToneCurve*)); + + if (NewElem ->TheCurves == NULL) goto Error; + + for (i=0; i < NewElem ->nCurves; i++) { + + // Duplicate each curve. It may fail. + NewElem ->TheCurves[i] = cmsDupToneCurve(Data ->TheCurves[i]); + if (NewElem ->TheCurves[i] == NULL) goto Error; + + + } + return (void*) NewElem; + +Error: + + if (NewElem ->TheCurves != NULL) { + for (i=0; i < NewElem ->nCurves; i++) { + if (NewElem ->TheCurves[i]) + cmsFreeToneCurve(NewElem ->TheCurves[i]); + } + } + _cmsFree(mpe ->ContextID, NewElem ->TheCurves); + _cmsFree(mpe ->ContextID, NewElem); + return NULL; +} + + +// Curves == NULL forces identity curves +cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[]) +{ + cmsUInt32Number i; + _cmsStageToneCurvesData* NewElem; + cmsStage* NewMPE; + + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels, + EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL ); + if (NewMPE == NULL) return NULL; + + NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(ContextID, sizeof(_cmsStageToneCurvesData)); + if (NewElem == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + NewMPE ->Data = (void*) NewElem; + + NewElem ->nCurves = nChannels; + NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*)); + if (NewElem ->TheCurves == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + for (i=0; i < nChannels; i++) { + + if (Curves == NULL) { + NewElem ->TheCurves[i] = cmsBuildGamma(ContextID, 1.0); + } + else { + NewElem ->TheCurves[i] = cmsDupToneCurve(Curves[i]); + } + + if (NewElem ->TheCurves[i] == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + } + + return NewMPE; +} + + +// Create a bunch of identity curves +cmsStage* CMSEXPORT _cmsStageAllocIdentityCurves(cmsContext ContextID, cmsUInt32Number nChannels) +{ + cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL); + + if (mpe == NULL) return NULL; + mpe ->Implements = cmsSigIdentityElemType; + return mpe; +} + + +// ************************************************************************************************* +// Type cmsSigMatrixElemType (Matrices) +// ************************************************************************************************* + + +// Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used +static +void EvaluateMatrix(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + cmsUInt32Number i, j; + _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + cmsFloat64Number Tmp; + + // Input is already in 0..1.0 notation + for (i=0; i < mpe ->OutputChannels; i++) { + + Tmp = 0; + for (j=0; j < mpe->InputChannels; j++) { + Tmp += In[j] * Data->Double[i*mpe->InputChannels + j]; + } + + if (Data ->Offset != NULL) + Tmp += Data->Offset[i]; + + Out[i] = (cmsFloat32Number) Tmp; + } + + + // Output in 0..1.0 domain +} + + +// Duplicate a yet-existing matrix element +static +void* MatrixElemDup(cmsStage* mpe) +{ + _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + _cmsStageMatrixData* NewElem; + cmsUInt32Number sz; + + NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData)); + if (NewElem == NULL) return NULL; + + sz = mpe ->InputChannels * mpe ->OutputChannels; + + NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ; + + if (Data ->Offset) + NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, + Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ; + + return (void*) NewElem; +} + + +static +void MatrixElemTypeFree(cmsStage* mpe) +{ + _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + if (Data == NULL) + return; + if (Data ->Double) + _cmsFree(mpe ->ContextID, Data ->Double); + + if (Data ->Offset) + _cmsFree(mpe ->ContextID, Data ->Offset); + + _cmsFree(mpe ->ContextID, mpe ->Data); +} + + + +cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, + const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset) +{ + cmsUInt32Number i, n; + _cmsStageMatrixData* NewElem; + cmsStage* NewMPE; + + n = Rows * Cols; + + // Check for overflow + if (n == 0) return NULL; + if (n >= UINT_MAX / Cols) return NULL; + if (n >= UINT_MAX / Rows) return NULL; + if (n < Rows || n < Cols) return NULL; + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigMatrixElemType, Cols, Rows, + EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL ); + if (NewMPE == NULL) return NULL; + + + NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData)); + if (NewElem == NULL) goto Error; + NewMPE->Data = (void*)NewElem; + + NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number)); + if (NewElem->Double == NULL) goto Error; + + for (i=0; i < n; i++) { + NewElem ->Double[i] = Matrix[i]; + } + + if (Offset != NULL) { + + NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Rows, sizeof(cmsFloat64Number)); + if (NewElem->Offset == NULL) goto Error; + + for (i=0; i < Rows; i++) { + NewElem ->Offset[i] = Offset[i]; + } + } + + return NewMPE; + +Error: + cmsStageFree(NewMPE); + return NULL; +} + + +// ************************************************************************************************* +// Type cmsSigCLutElemType +// ************************************************************************************************* + + +// Evaluate in true floating point +static +void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + + Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params); +} + + +// Convert to 16 bits, evaluate, and back to floating point +static +void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS]; + + _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS); + _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS); + + FromFloatTo16(In, In16, mpe ->InputChannels); + Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params); + From16ToFloat(Out16, Out, mpe ->OutputChannels); +} + + +// Given an hypercube of b dimensions, with Dims[] number of nodes by dimension, calculate the total amount of nodes +static +cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) +{ + cmsUInt32Number rv, dim; + + _cmsAssert(Dims != NULL); + + for (rv = 1; b > 0; b--) { + + dim = Dims[b-1]; + if (dim == 0) return 0; // Error + + rv *= dim; + + // Check for overflow + if (rv > UINT_MAX / dim) return 0; + } + + return rv; +} + +static +void* CLUTElemDup(cmsStage* mpe) +{ + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + _cmsStageCLutData* NewElem; + + + NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData)); + if (NewElem == NULL) return NULL; + + NewElem ->nEntries = Data ->nEntries; + NewElem ->HasFloatValues = Data ->HasFloatValues; + + if (Data ->Tab.T) { + + if (Data ->HasFloatValues) { + NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); + if (NewElem ->Tab.TFloat == NULL) + goto Error; + } else { + NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); + if (NewElem ->Tab.T == NULL) + goto Error; + } + } + + NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, + Data ->Params ->nSamples, + Data ->Params ->nInputs, + Data ->Params ->nOutputs, + NewElem ->Tab.T, + Data ->Params ->dwFlags); + if (NewElem->Params != NULL) + return (void*) NewElem; + Error: + if (NewElem->Tab.T) + // This works for both types + _cmsFree(mpe ->ContextID, NewElem -> Tab.T); + _cmsFree(mpe ->ContextID, NewElem); + return NULL; +} + + +static +void CLutElemTypeFree(cmsStage* mpe) +{ + + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + + // Already empty + if (Data == NULL) return; + + // This works for both types + if (Data -> Tab.T) + _cmsFree(mpe ->ContextID, Data -> Tab.T); + + _cmsFreeInterpParams(Data ->Params); + _cmsFree(mpe ->ContextID, mpe ->Data); +} + + +// Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different +// granularity on each dimension. +cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, + const cmsUInt32Number clutPoints[], + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, + const cmsUInt16Number* Table) +{ + cmsUInt32Number i, n; + _cmsStageCLutData* NewElem; + cmsStage* NewMPE; + + _cmsAssert(clutPoints != NULL); + + if (inputChan > MAX_INPUT_DIMENSIONS) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); + return NULL; + } + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, + EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL ); + + if (NewMPE == NULL) return NULL; + + NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); + if (NewElem == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + NewMPE ->Data = (void*) NewElem; + + NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); + NewElem -> HasFloatValues = FALSE; + + if (n == 0) { + cmsStageFree(NewMPE); + return NULL; + } + + + NewElem ->Tab.T = (cmsUInt16Number*) _cmsCalloc(ContextID, n, sizeof(cmsUInt16Number)); + if (NewElem ->Tab.T == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + if (Table != NULL) { + for (i=0; i < n; i++) { + NewElem ->Tab.T[i] = Table[i]; + } + } + + NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.T, CMS_LERP_FLAGS_16BITS); + if (NewElem ->Params == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + return NewMPE; +} + +cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, + cmsUInt32Number nGridPoints, + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, + const cmsUInt16Number* Table) +{ + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + int i; + + // Our resulting LUT would be same gridpoints on all dimensions + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + Dimensions[i] = nGridPoints; + + return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); +} + + +cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, + cmsUInt32Number nGridPoints, + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, + const cmsFloat32Number* Table) +{ + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + int i; + + // Our resulting LUT would be same gridpoints on all dimensions + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + Dimensions[i] = nGridPoints; + + return cmsStageAllocCLutFloatGranular(ContextID, Dimensions, inputChan, outputChan, Table); +} + + + +cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table) +{ + cmsUInt32Number i, n; + _cmsStageCLutData* NewElem; + cmsStage* NewMPE; + + _cmsAssert(clutPoints != NULL); + + if (inputChan > MAX_INPUT_DIMENSIONS) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); + return NULL; + } + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, + EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); + if (NewMPE == NULL) return NULL; + + + NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); + if (NewElem == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + NewMPE ->Data = (void*) NewElem; + + // There is a potential integer overflow on conputing n and nEntries. + NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); + NewElem -> HasFloatValues = TRUE; + + if (n == 0) { + cmsStageFree(NewMPE); + return NULL; + } + + NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat32Number)); + if (NewElem ->Tab.TFloat == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + if (Table != NULL) { + for (i=0; i < n; i++) { + NewElem ->Tab.TFloat[i] = Table[i]; + } + } + + NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); + if (NewElem ->Params == NULL) { + cmsStageFree(NewMPE); + return NULL; + } + + return NewMPE; +} + + +static +int IdentitySampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void * Cargo) +{ + int nChan = *(int*) Cargo; + int i; + + for (i=0; i < nChan; i++) + Out[i] = In[i]; + + return 1; +} + +// Creates an MPE that just copies input to output +cmsStage* CMSEXPORT _cmsStageAllocIdentityCLut(cmsContext ContextID, cmsUInt32Number nChan) +{ + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + cmsStage* mpe ; + int i; + + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) + Dimensions[i] = 2; + + mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL); + if (mpe == NULL) return NULL; + + if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) { + cmsStageFree(mpe); + return NULL; + } + + mpe ->Implements = cmsSigIdentityElemType; + return mpe; +} + + + +// Quantize a value 0 <= i < MaxSamples to 0..0xffff +cmsUInt16Number CMSEXPORT _cmsQuantizeVal(cmsFloat64Number i, cmsUInt32Number MaxSamples) +{ + cmsFloat64Number x; + + x = ((cmsFloat64Number) i * 65535.) / (cmsFloat64Number) (MaxSamples - 1); + return _cmsQuickSaturateWord(x); +} + + +// This routine does a sweep on whole input space, and calls its callback +// function on knots. returns TRUE if all ok, FALSE otherwise. +cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags) +{ + int i, t, index, rest; + cmsUInt32Number nTotalPoints; + cmsUInt32Number nInputs, nOutputs; + cmsUInt32Number* nSamples; + cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; + _cmsStageCLutData* clut; + + if (mpe == NULL) return FALSE; + + clut = (_cmsStageCLutData*) mpe->Data; + + if (clut == NULL) return FALSE; + + nSamples = clut->Params ->nSamples; + nInputs = clut->Params ->nInputs; + nOutputs = clut->Params ->nOutputs; + + if (nInputs <= 0) return FALSE; + if (nOutputs <= 0) return FALSE; + if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; + if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; + + memset(In, 0, sizeof(In)); + memset(Out, 0, sizeof(Out)); + + nTotalPoints = CubeSize(nSamples, nInputs); + if (nTotalPoints == 0) return FALSE; + + index = 0; + for (i = 0; i < (int) nTotalPoints; i++) { + + rest = i; + for (t = (int)nInputs - 1; t >= 0; --t) { + + cmsUInt32Number Colorant = rest % nSamples[t]; + + rest /= nSamples[t]; + + In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); + } + + if (clut ->Tab.T != NULL) { + for (t = 0; t < (int)nOutputs; t++) + Out[t] = clut->Tab.T[index + t]; + } + + if (!Sampler(In, Out, Cargo)) + return FALSE; + + if (!(dwFlags & SAMPLER_INSPECT)) { + + if (clut ->Tab.T != NULL) { + for (t=0; t < (int) nOutputs; t++) + clut->Tab.T[index + t] = Out[t]; + } + } + + index += nOutputs; + } + + return TRUE; +} + +// Same as anterior, but for floating point +cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void * Cargo, cmsUInt32Number dwFlags) +{ + int i, t, index, rest; + cmsUInt32Number nTotalPoints; + cmsUInt32Number nInputs, nOutputs; + cmsUInt32Number* nSamples; + cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; + _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + + nSamples = clut->Params ->nSamples; + nInputs = clut->Params ->nInputs; + nOutputs = clut->Params ->nOutputs; + + if (nInputs <= 0) return FALSE; + if (nOutputs <= 0) return FALSE; + if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; + if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; + + nTotalPoints = CubeSize(nSamples, nInputs); + if (nTotalPoints == 0) return FALSE; + + index = 0; + for (i = 0; i < (int)nTotalPoints; i++) { + + rest = i; + for (t = (int) nInputs-1; t >=0; --t) { + + cmsUInt32Number Colorant = rest % nSamples[t]; + + rest /= nSamples[t]; + + In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); + } + + if (clut ->Tab.TFloat != NULL) { + for (t=0; t < (int) nOutputs; t++) + Out[t] = clut->Tab.TFloat[index + t]; + } + + if (!Sampler(In, Out, Cargo)) + return FALSE; + + if (!(dwFlags & SAMPLER_INSPECT)) { + + if (clut ->Tab.TFloat != NULL) { + for (t=0; t < (int) nOutputs; t++) + clut->Tab.TFloat[index + t] = Out[t]; + } + } + + index += nOutputs; + } + + return TRUE; +} + + + +// This routine does a sweep on whole input space, and calls its callback +// function on knots. returns TRUE if all ok, FALSE otherwise. +cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], + cmsSAMPLER16 Sampler, void * Cargo) +{ + int i, t, rest; + cmsUInt32Number nTotalPoints; + cmsUInt16Number In[cmsMAXCHANNELS]; + + if (nInputs >= cmsMAXCHANNELS) return FALSE; + + nTotalPoints = CubeSize(clutPoints, nInputs); + if (nTotalPoints == 0) return FALSE; + + for (i = 0; i < (int) nTotalPoints; i++) { + + rest = i; + for (t = (int) nInputs-1; t >=0; --t) { + + cmsUInt32Number Colorant = rest % clutPoints[t]; + + rest /= clutPoints[t]; + In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); + + } + + if (!Sampler(In, NULL, Cargo)) + return FALSE; + } + + return TRUE; +} + +cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], + cmsSAMPLERFLOAT Sampler, void * Cargo) +{ + int i, t, rest; + cmsUInt32Number nTotalPoints; + cmsFloat32Number In[cmsMAXCHANNELS]; + + if (nInputs >= cmsMAXCHANNELS) return FALSE; + + nTotalPoints = CubeSize(clutPoints, nInputs); + if (nTotalPoints == 0) return FALSE; + + for (i = 0; i < (int) nTotalPoints; i++) { + + rest = i; + for (t = (int) nInputs-1; t >=0; --t) { + + cmsUInt32Number Colorant = rest % clutPoints[t]; + + rest /= clutPoints[t]; + In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); + + } + + if (!Sampler(In, NULL, Cargo)) + return FALSE; + } + + return TRUE; +} + +// ******************************************************************************** +// Type cmsSigLab2XYZElemType +// ******************************************************************************** + + +static +void EvaluateLab2XYZ(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + cmsCIELab Lab; + cmsCIEXYZ XYZ; + const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; + + // V4 rules + Lab.L = In[0] * 100.0; + Lab.a = In[1] * 255.0 - 128.0; + Lab.b = In[2] * 255.0 - 128.0; + + cmsLab2XYZ(NULL, &XYZ, &Lab); + + // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff + // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0) + + Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); + Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); + Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); + return; + + cmsUNUSED_PARAMETER(mpe); +} + + +// No dup or free routines needed, as the structure has no pointers in it. +cmsStage* CMSEXPORT _cmsStageAllocLab2XYZ(cmsContext ContextID) +{ + return _cmsStageAllocPlaceholder(ContextID, cmsSigLab2XYZElemType, 3, 3, EvaluateLab2XYZ, NULL, NULL, NULL); +} + +// ******************************************************************************** + +// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable +// number of gridpoints that would make exact match. However, a prelinearization +// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. +// Almost all what we need but unfortunately, the rest of entries should be scaled by +// (255*257/256) and this is not exact. + +cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) +{ + cmsStage* mpe; + cmsToneCurve* LabTable[3]; + int i, j; + + LabTable[0] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); + LabTable[1] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); + LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); + + for (j=0; j < 3; j++) { + + if (LabTable[j] == NULL) { + cmsFreeToneCurveTriple(LabTable); + return NULL; + } + + // We need to map * (0xffff / 0xff00), that's same as (257 / 256) + // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256); + for (i=0; i < 257; i++) { + + LabTable[j]->Table16[i] = (cmsUInt16Number) ((i * 0xffff + 0x80) >> 8); + } + + LabTable[j] ->Table16[257] = 0xffff; + } + + mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); + cmsFreeToneCurveTriple(LabTable); + + if (mpe == NULL) return NULL; + mpe ->Implements = cmsSigLabV2toV4; + return mpe; +} + +// ******************************************************************************** + +// Matrix-based conversion, which is more accurate, but slower and cannot properly be saved in devicelink profiles +cmsStage* CMSEXPORT _cmsStageAllocLabV2ToV4(cmsContext ContextID) +{ + static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0, + 0, 65535.0/65280.0, 0, + 0, 0, 65535.0/65280.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigLabV2toV4; + return mpe; +} + + +// Reverse direction +cmsStage* CMSEXPORT _cmsStageAllocLabV4ToV2(cmsContext ContextID) +{ + static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0, + 0, 65280.0/65535.0, 0, + 0, 0, 65280.0/65535.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigLabV4toV2; + return mpe; +} + + +// To Lab to float. Note that the MPE gives numbers in normal Lab range +// and we need 0..1.0 range for the formatters +// L* : 0...100 => 0...1.0 (L* / 100) +// ab* : -128..+127 to 0..1 ((ab* + 128) / 255) + +cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID) +{ + static const cmsFloat64Number a1[] = { + 1.0/100.0, 0, 0, + 0, 1.0/255.0, 0, + 0, 0, 1.0/255.0 + }; + + static const cmsFloat64Number o1[] = { + 0, + 128.0/255.0, + 128.0/255.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigLab2FloatPCS; + return mpe; +} + +// Fom XYZ to floating point PCS +cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID) +{ +#define n (32768.0/65535.0) + static const cmsFloat64Number a1[] = { + n, 0, 0, + 0, n, 0, + 0, 0, n + }; +#undef n + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigXYZ2FloatPCS; + return mpe; +} + +cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID) +{ + static const cmsFloat64Number a1[] = { + 100.0, 0, 0, + 0, 255.0, 0, + 0, 0, 255.0 + }; + + static const cmsFloat64Number o1[] = { + 0, + -128.0, + -128.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigFloatPCS2Lab; + return mpe; +} + +cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID) +{ +#define n (65535.0/32768.0) + + static const cmsFloat64Number a1[] = { + n, 0, 0, + 0, n, 0, + 0, 0, n + }; +#undef n + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigFloatPCS2XYZ; + return mpe; +} + +// Clips values smaller than zero +static +void Clipper(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + cmsUInt32Number i; + for (i = 0; i < mpe->InputChannels; i++) { + + cmsFloat32Number n = In[i]; + Out[i] = n < 0 ? 0 : n; + } +} + +cmsStage* _cmsStageClipNegatives(cmsContext ContextID, cmsUInt32Number nChannels) +{ + return _cmsStageAllocPlaceholder(ContextID, cmsSigClipNegativesElemType, + nChannels, nChannels, Clipper, NULL, NULL, NULL); +} + +// ******************************************************************************** +// Type cmsSigXYZ2LabElemType +// ******************************************************************************** + +static +void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + cmsCIELab Lab; + cmsCIEXYZ XYZ; + const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; + + // From 0..1.0 to XYZ + + XYZ.X = In[0] * XYZadj; + XYZ.Y = In[1] * XYZadj; + XYZ.Z = In[2] * XYZadj; + + cmsXYZ2Lab(NULL, &Lab, &XYZ); + + // From V4 Lab to 0..1.0 + + Out[0] = (cmsFloat32Number) (Lab.L / 100.0); + Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); + Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0); + return; + + cmsUNUSED_PARAMETER(mpe); +} + +cmsStage* CMSEXPORT _cmsStageAllocXYZ2Lab(cmsContext ContextID) +{ + return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL); + +} + +// ******************************************************************************** + +// For v4, S-Shaped curves are placed in a/b axis to increase resolution near gray + +cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID) +{ + cmsToneCurve* LabTable[3]; + cmsFloat64Number Params[1] = {2.4} ; + + LabTable[0] = cmsBuildGamma(ContextID, 1.0); + LabTable[1] = cmsBuildParametricToneCurve(ContextID, 108, Params); + LabTable[2] = cmsBuildParametricToneCurve(ContextID, 108, Params); + + return cmsStageAllocToneCurves(ContextID, 3, LabTable); +} + + +// Free a single MPE +void CMSEXPORT cmsStageFree(cmsStage* mpe) +{ + if (mpe ->FreePtr) + mpe ->FreePtr(mpe); + + _cmsFree(mpe ->ContextID, mpe); +} + + +cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe) +{ + return mpe ->InputChannels; +} + +cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe) +{ + return mpe ->OutputChannels; +} + +cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe) +{ + return mpe -> Type; +} + +void* CMSEXPORT cmsStageData(const cmsStage* mpe) +{ + return mpe -> Data; +} + +cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) +{ + return mpe -> Next; +} + + +// Duplicates an MPE +cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) +{ + cmsStage* NewMPE; + + if (mpe == NULL) return NULL; + NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, + mpe ->Type, + mpe ->InputChannels, + mpe ->OutputChannels, + mpe ->EvalPtr, + mpe ->DupElemPtr, + mpe ->FreePtr, + NULL); + if (NewMPE == NULL) return NULL; + + NewMPE ->Implements = mpe ->Implements; + + if (mpe ->DupElemPtr) { + + NewMPE ->Data = mpe ->DupElemPtr(mpe); + + if (NewMPE->Data == NULL) { + + cmsStageFree(NewMPE); + return NULL; + } + + } else { + + NewMPE ->Data = NULL; + } + + return NewMPE; +} + + +// *********************************************************************************************************** + +// This function sets up the channel count +static +cmsBool BlessLUT(cmsPipeline* lut) +{ + // We can set the input/output channels only if we have elements. + if (lut ->Elements != NULL) { + + cmsStage* prev; + cmsStage* next; + cmsStage* First; + cmsStage* Last; + + First = cmsPipelineGetPtrToFirstStage(lut); + Last = cmsPipelineGetPtrToLastStage(lut); + + if (First == NULL || Last == NULL) return FALSE; + + lut->InputChannels = First->InputChannels; + lut->OutputChannels = Last->OutputChannels; + + // Check chain consistency + prev = First; + next = prev->Next; + + while (next != NULL) + { + if (next->InputChannels != prev->OutputChannels) + return FALSE; + + next = next->Next; + prev = prev->Next; + } +} + + return TRUE; +} + + +// Default to evaluate the LUT on 16 bit-basis. Precision is retained. +static +void _LUTeval16(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER const void* D) +{ + cmsPipeline* lut = (cmsPipeline*) D; + cmsStage *mpe; + cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; + int Phase = 0, NextPhase; + + From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); + + for (mpe = lut ->Elements; + mpe != NULL; + mpe = mpe ->Next) { + + NextPhase = Phase ^ 1; + mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); + Phase = NextPhase; + } + + + FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels); +} + + + +// Does evaluate the LUT on cmsFloat32Number-basis. +static +void _LUTevalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const void* D) +{ + cmsPipeline* lut = (cmsPipeline*) D; + cmsStage *mpe; + cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; + int Phase = 0, NextPhase; + + memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); + + for (mpe = lut ->Elements; + mpe != NULL; + mpe = mpe ->Next) { + + NextPhase = Phase ^ 1; + mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); + Phase = NextPhase; + } + + memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number)); +} + + +// LUT Creation & Destruction +cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels) +{ + cmsPipeline* NewLUT; + + // A value of zero in channels is allowed as placeholder + if (InputChannels >= cmsMAXCHANNELS || + OutputChannels >= cmsMAXCHANNELS) return NULL; + + NewLUT = (cmsPipeline*) _cmsMallocZero(ContextID, sizeof(cmsPipeline)); + if (NewLUT == NULL) return NULL; + + NewLUT -> InputChannels = InputChannels; + NewLUT -> OutputChannels = OutputChannels; + + NewLUT ->Eval16Fn = _LUTeval16; + NewLUT ->EvalFloatFn = _LUTevalFloat; + NewLUT ->DupDataFn = NULL; + NewLUT ->FreeDataFn = NULL; + NewLUT ->Data = NewLUT; + NewLUT ->ContextID = ContextID; + + if (!BlessLUT(NewLUT)) + { + _cmsFree(ContextID, NewLUT); + return NULL; + } + + return NewLUT; +} + +cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut) +{ + _cmsAssert(lut != NULL); + return lut ->ContextID; +} + +cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut) +{ + _cmsAssert(lut != NULL); + return lut ->InputChannels; +} + +cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut) +{ + _cmsAssert(lut != NULL); + return lut ->OutputChannels; +} + +// Free a profile elements LUT +void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) +{ + cmsStage *mpe, *Next; + + if (lut == NULL) return; + + for (mpe = lut ->Elements; + mpe != NULL; + mpe = Next) { + + Next = mpe ->Next; + cmsStageFree(mpe); + } + + if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data); + + _cmsFree(lut ->ContextID, lut); +} + + +// Default to evaluate the LUT on 16 bit-basis. +void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut) +{ + _cmsAssert(lut != NULL); + lut ->Eval16Fn(In, Out, lut->Data); +} + + +// Does evaluate the LUT on cmsFloat32Number-basis. +void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut) +{ + _cmsAssert(lut != NULL); + lut ->EvalFloatFn(In, Out, lut); +} + + + +// Duplicates a LUT +cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) +{ + cmsPipeline* NewLUT; + cmsStage *NewMPE, *Anterior = NULL, *mpe; + cmsBool First = TRUE; + + if (lut == NULL) return NULL; + + NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); + if (NewLUT == NULL) return NULL; + + for (mpe = lut ->Elements; + mpe != NULL; + mpe = mpe ->Next) { + + NewMPE = cmsStageDup(mpe); + + if (NewMPE == NULL) { + cmsPipelineFree(NewLUT); + return NULL; + } + + if (First) { + NewLUT ->Elements = NewMPE; + First = FALSE; + } + else { + if (Anterior != NULL) + Anterior ->Next = NewMPE; + } + + Anterior = NewMPE; + } + + NewLUT ->Eval16Fn = lut ->Eval16Fn; + NewLUT ->EvalFloatFn = lut ->EvalFloatFn; + NewLUT ->DupDataFn = lut ->DupDataFn; + NewLUT ->FreeDataFn = lut ->FreeDataFn; + + if (NewLUT ->DupDataFn != NULL) + NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data); + + + NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits; + + if (!BlessLUT(NewLUT)) + { + _cmsFree(lut->ContextID, NewLUT); + return NULL; + } + + return NewLUT; +} + + +int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) +{ + cmsStage* Anterior = NULL, *pt; + + if (lut == NULL || mpe == NULL) + return FALSE; + + switch (loc) { + + case cmsAT_BEGIN: + mpe ->Next = lut ->Elements; + lut ->Elements = mpe; + break; + + case cmsAT_END: + + if (lut ->Elements == NULL) + lut ->Elements = mpe; + else { + + for (pt = lut ->Elements; + pt != NULL; + pt = pt -> Next) Anterior = pt; + + Anterior ->Next = mpe; + mpe ->Next = NULL; + } + break; + default:; + return FALSE; + } + + return BlessLUT(lut); +} + +// Unlink an element and return the pointer to it +void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe) +{ + cmsStage *Anterior, *pt, *Last; + cmsStage *Unlinked = NULL; + + + // If empty LUT, there is nothing to remove + if (lut ->Elements == NULL) { + if (mpe) *mpe = NULL; + return; + } + + // On depending on the strategy... + switch (loc) { + + case cmsAT_BEGIN: + { + cmsStage* elem = lut ->Elements; + + lut ->Elements = elem -> Next; + elem ->Next = NULL; + Unlinked = elem; + + } + break; + + case cmsAT_END: + Anterior = Last = NULL; + for (pt = lut ->Elements; + pt != NULL; + pt = pt -> Next) { + Anterior = Last; + Last = pt; + } + + Unlinked = Last; // Next already points to NULL + + // Truncate the chain + if (Anterior) + Anterior ->Next = NULL; + else + lut ->Elements = NULL; + break; + default:; + } + + if (mpe) + *mpe = Unlinked; + else + cmsStageFree(Unlinked); + + // May fail, but we ignore it + BlessLUT(lut); +} + + +// Concatenate two LUT into a new single one +cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) +{ + cmsStage* mpe; + + // If both LUTS does not have elements, we need to inherit + // the number of channels + if (l1 ->Elements == NULL && l2 ->Elements == NULL) { + l1 ->InputChannels = l2 ->InputChannels; + l1 ->OutputChannels = l2 ->OutputChannels; + } + + // Cat second + for (mpe = l2 ->Elements; + mpe != NULL; + mpe = mpe ->Next) { + + // We have to dup each element + if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe))) + return FALSE; + } + + return BlessLUT(l1); +} + + +cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On) +{ + cmsBool Anterior = lut ->SaveAs8Bits; + + lut ->SaveAs8Bits = On; + return Anterior; +} + + +cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut) +{ + return lut ->Elements; +} + +cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut) +{ + cmsStage *mpe, *Anterior = NULL; + + for (mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) + Anterior = mpe; + + return Anterior; +} + +cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) +{ + cmsStage *mpe; + cmsUInt32Number n; + + for (n=0, mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) + n++; + + return n; +} + +// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional +// duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. +void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, + _cmsPipelineEval16Fn Eval16, + void* PrivateData, + _cmsFreeUserDataFn FreePrivateDataFn, + _cmsDupUserDataFn DupPrivateDataFn) +{ + + Lut ->Eval16Fn = Eval16; + Lut ->DupDataFn = DupPrivateDataFn; + Lut ->FreeDataFn = FreePrivateDataFn; + Lut ->Data = PrivateData; +} + + +// ----------------------------------------------------------- Reverse interpolation +// Here's how it goes. The derivative Df(x) of the function f is the linear +// transformation that best approximates f near the point x. It can be represented +// by a matrix A whose entries are the partial derivatives of the components of f +// with respect to all the coordinates. This is know as the Jacobian +// +// The best linear approximation to f is given by the matrix equation: +// +// y-y0 = A (x-x0) +// +// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this +// linear approximation will give a "better guess" for the zero of f. Thus let y=0, +// and since y0=f(x0) one can solve the above equation for x. This leads to the +// Newton's method formula: +// +// xn+1 = xn - A-1 f(xn) +// +// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the +// fashion described above. Iterating this will give better and better approximations +// if you have a "good enough" initial guess. + + +#define JACOBIAN_EPSILON 0.001f +#define INVERSION_MAX_ITERATIONS 30 + +// Increment with reflexion on boundary +static +void IncDelta(cmsFloat32Number *Val) +{ + if (*Val < (1.0 - JACOBIAN_EPSILON)) + + *Val += JACOBIAN_EPSILON; + + else + *Val -= JACOBIAN_EPSILON; + +} + + + +// Euclidean distance between two vectors of n elements each one +static +cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], int n) +{ + cmsFloat32Number sum = 0; + int i; + + for (i=0; i < n; i++) { + cmsFloat32Number dif = b[i] - a[i]; + sum += dif * dif; + } + + return sqrtf(sum); +} + + +// Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method +// +// x1 <- x - [J(x)]^-1 * f(x) +// +// lut: The LUT on where to do the search +// Target: LabK, 3 values of Lab plus destination K which is fixed +// Result: The obtained CMYK +// Hint: Location where begin the search + +cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], + cmsFloat32Number Result[], + cmsFloat32Number Hint[], + const cmsPipeline* lut) +{ + cmsUInt32Number i, j; + cmsFloat64Number error, LastError = 1E20; + cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; + cmsVEC3 tmp, tmp2; + cmsMAT3 Jacobian; + + // Only 3->3 and 4->3 are supported + if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; + if (lut ->OutputChannels != 3) return FALSE; + + // Take the hint as starting point if specified + if (Hint == NULL) { + + // Begin at any point, we choose 1/3 of CMY axis + x[0] = x[1] = x[2] = 0.3f; + } + else { + + // Only copy 3 channels from hint... + for (j=0; j < 3; j++) + x[j] = Hint[j]; + } + + // If Lut is 4-dimensions, then grab target[3], which is fixed + if (lut ->InputChannels == 4) { + x[3] = Target[3]; + } + else x[3] = 0; // To keep lint happy + + + // Iterate + for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) { + + // Get beginning fx + cmsPipelineEvalFloat(x, fx, lut); + + // Compute error + error = EuclideanDistance(fx, Target, 3); + + // If not convergent, return last safe value + if (error >= LastError) + break; + + // Keep latest values + LastError = error; + for (j=0; j < lut ->InputChannels; j++) + Result[j] = x[j]; + + // Found an exact match? + if (error <= 0) + break; + + // Obtain slope (the Jacobian) + for (j = 0; j < 3; j++) { + + xd[0] = x[0]; + xd[1] = x[1]; + xd[2] = x[2]; + xd[3] = x[3]; // Keep fixed channel + + IncDelta(&xd[j]); + + cmsPipelineEvalFloat(xd, fxd, lut); + + Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON); + Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON); + Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); + } + + // Solve system + tmp2.n[0] = fx[0] - Target[0]; + tmp2.n[1] = fx[1] - Target[1]; + tmp2.n[2] = fx[2] - Target[2]; + + if (!_cmsMAT3solve(&tmp, &Jacobian, &tmp2)) + return FALSE; + + // Move our guess + x[0] -= (cmsFloat32Number) tmp.n[0]; + x[1] -= (cmsFloat32Number) tmp.n[1]; + x[2] -= (cmsFloat32Number) tmp.n[2]; + + // Some clipping.... + for (j=0; j < 3; j++) { + if (x[j] < 0) x[j] = 0; + else + if (x[j] > 1.0) x[j] = 1.0; + } + } + + return TRUE; +} + + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsmd5.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsmd5.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsmd5.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsmd5.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,342 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- + + +#include "lcms2_internal.h" + +#ifdef CMS_USE_BIG_ENDIAN + +static +void byteReverse(cmsUInt8Number * buf, cmsUInt32Number longs) +{ + do { + + cmsUInt32Number t = _cmsAdjustEndianess32(*(cmsUInt32Number *) buf); + *(cmsUInt32Number *) buf = t; + buf += sizeof(cmsUInt32Number); + + } while (--longs); + +} + +#else +#define byteReverse(buf, len) +#endif + + +typedef struct { + + cmsUInt32Number buf[4]; + cmsUInt32Number bits[2]; + cmsUInt8Number in[64]; + cmsContext ContextID; + +} _cmsMD5; + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + + +static +void cmsMD5_Transform(cmsUInt32Number buf[4], cmsUInt32Number in[16]) +{ + CMSREGISTER cmsUInt32Number a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + + +// Create a MD5 object + +cmsHANDLE CMSEXPORT cmsMD5alloc(cmsContext ContextID) +{ + _cmsMD5* ctx = (_cmsMD5*) _cmsMallocZero(ContextID, sizeof(_cmsMD5)); + if (ctx == NULL) return NULL; + + ctx ->ContextID = ContextID; + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; + + return (cmsHANDLE) ctx; +} + +void CMSEXPORT cmsMD5add(cmsHANDLE Handle, const cmsUInt8Number* buf, cmsUInt32Number len) +{ + _cmsMD5* ctx = (_cmsMD5*) Handle; + cmsUInt32Number t; + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + (len << 3)) < t) + ctx->bits[1]++; + + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; + + if (t) { + + cmsUInt8Number *p = (cmsUInt8Number *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memmove(p, buf, len); + return; + } + + memmove(p, buf, t); + byteReverse(ctx->in, 16); + + cmsMD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); + buf += t; + len -= t; + } + + while (len >= 64) { + memmove(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + cmsMD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); + buf += 64; + len -= 64; + } + + memmove(ctx->in, buf, len); +} + +// Destroy the object and return the checksum +void CMSEXPORT cmsMD5finish(cmsProfileID* ProfileID, cmsHANDLE Handle) +{ + _cmsMD5* ctx = (_cmsMD5*) Handle; + cmsUInt32Number count; + cmsUInt8Number *p; + + count = (ctx->bits[0] >> 3) & 0x3F; + + p = ctx->in + count; + *p++ = 0x80; + + count = 64 - 1 - count; + + if (count < 8) { + + memset(p, 0, count); + byteReverse(ctx->in, 16); + cmsMD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); + + memset(ctx->in, 0, 56); + } else { + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + ((cmsUInt32Number *) ctx->in)[14] = ctx->bits[0]; + ((cmsUInt32Number *) ctx->in)[15] = ctx->bits[1]; + + cmsMD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in); + + byteReverse((cmsUInt8Number *) ctx->buf, 4); + memmove(ProfileID ->ID8, ctx->buf, 16); + + _cmsFree(ctx ->ContextID, ctx); +} + + + +// Assuming io points to an ICC profile, compute and store MD5 checksum +// In the header, rendering intentent, attributes and ID should be set to zero +// before computing MD5 checksum (per 6.1.13 in ICC spec) + +cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile) +{ + cmsContext ContextID; + cmsUInt32Number BytesNeeded; + cmsUInt8Number* Mem = NULL; + cmsHANDLE MD5 = NULL; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE Keep; + + _cmsAssert(hProfile != NULL); + + ContextID = cmsGetProfileContextID(hProfile); + + // Save a copy of the profile header + memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); + + // Set RI, attributes and ID + memset(&Icc ->attributes, 0, sizeof(Icc ->attributes)); + Icc ->RenderingIntent = 0; + memset(&Icc ->ProfileID, 0, sizeof(Icc ->ProfileID)); + + // Compute needed storage + if (!cmsSaveProfileToMem(hProfile, NULL, &BytesNeeded)) goto Error; + + // Allocate memory + Mem = (cmsUInt8Number*) _cmsMalloc(ContextID, BytesNeeded); + if (Mem == NULL) goto Error; + + // Save to temporary storage + if (!cmsSaveProfileToMem(hProfile, Mem, &BytesNeeded)) goto Error; + + // Create MD5 object + MD5 = cmsMD5alloc(ContextID); + if (MD5 == NULL) goto Error; + + // Add all bytes + cmsMD5add(MD5, Mem, BytesNeeded); + + // Temp storage is no longer needed + _cmsFree(ContextID, Mem); + + // Restore header + memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + + // And store the ID + cmsMD5finish(&Icc ->ProfileID, MD5); + return TRUE; + +Error: + + // Free resources as something went wrong + // "MD5" cannot be other than NULL here, so no need to free it + if (Mem != NULL) _cmsFree(ContextID, Mem); + memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + return FALSE; +} + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsmtrx.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsmtrx.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsmtrx.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsmtrx.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,205 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +#define DSWAP(x, y) {cmsFloat64Number tmp = (x); (x)=(y); (y)=tmp;} + + +// Initiate a vector +void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z) +{ + r -> n[VX] = x; + r -> n[VY] = y; + r -> n[VZ] = z; +} + +// Vector subtraction +void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b) +{ + r -> n[VX] = a -> n[VX] - b -> n[VX]; + r -> n[VY] = a -> n[VY] - b -> n[VY]; + r -> n[VZ] = a -> n[VZ] - b -> n[VZ]; +} + +// Vector cross product +void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v) +{ + r ->n[VX] = u->n[VY] * v->n[VZ] - v->n[VY] * u->n[VZ]; + r ->n[VY] = u->n[VZ] * v->n[VX] - v->n[VZ] * u->n[VX]; + r ->n[VZ] = u->n[VX] * v->n[VY] - v->n[VX] * u->n[VY]; +} + +// Vector dot product +cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v) +{ + return u->n[VX] * v->n[VX] + u->n[VY] * v->n[VY] + u->n[VZ] * v->n[VZ]; +} + +// Euclidean length +cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a) +{ + return sqrt(a ->n[VX] * a ->n[VX] + + a ->n[VY] * a ->n[VY] + + a ->n[VZ] * a ->n[VZ]); +} + +// Euclidean distance +cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b) +{ + cmsFloat64Number d1 = a ->n[VX] - b ->n[VX]; + cmsFloat64Number d2 = a ->n[VY] - b ->n[VY]; + cmsFloat64Number d3 = a ->n[VZ] - b ->n[VZ]; + + return sqrt(d1*d1 + d2*d2 + d3*d3); +} + + + +// 3x3 Identity +void CMSEXPORT _cmsMAT3identity(cmsMAT3* a) +{ + _cmsVEC3init(&a-> v[0], 1.0, 0.0, 0.0); + _cmsVEC3init(&a-> v[1], 0.0, 1.0, 0.0); + _cmsVEC3init(&a-> v[2], 0.0, 0.0, 1.0); +} + +static +cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b) +{ + return fabs(b - a) < (1.0 / 65535.0); +} + + +cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a) +{ + cmsMAT3 Identity; + int i, j; + + _cmsMAT3identity(&Identity); + + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + if (!CloseEnough(a ->v[i].n[j], Identity.v[i].n[j])) return FALSE; + + return TRUE; +} + + +// Multiply two matrices +void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b) +{ +#define ROWCOL(i, j) \ + a->v[i].n[0]*b->v[0].n[j] + a->v[i].n[1]*b->v[1].n[j] + a->v[i].n[2]*b->v[2].n[j] + + _cmsVEC3init(&r-> v[0], ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2)); + _cmsVEC3init(&r-> v[1], ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2)); + _cmsVEC3init(&r-> v[2], ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2)); + +#undef ROWCOL //(i, j) +} + + + +// Inverse of a matrix b = a^(-1) +cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b) +{ + cmsFloat64Number det, c0, c1, c2; + + c0 = a -> v[1].n[1]*a -> v[2].n[2] - a -> v[1].n[2]*a -> v[2].n[1]; + c1 = -a -> v[1].n[0]*a -> v[2].n[2] + a -> v[1].n[2]*a -> v[2].n[0]; + c2 = a -> v[1].n[0]*a -> v[2].n[1] - a -> v[1].n[1]*a -> v[2].n[0]; + + det = a -> v[0].n[0]*c0 + a -> v[0].n[1]*c1 + a -> v[0].n[2]*c2; + + if (fabs(det) < MATRIX_DET_TOLERANCE) return FALSE; // singular matrix; can't invert + + b -> v[0].n[0] = c0/det; + b -> v[0].n[1] = (a -> v[0].n[2]*a -> v[2].n[1] - a -> v[0].n[1]*a -> v[2].n[2])/det; + b -> v[0].n[2] = (a -> v[0].n[1]*a -> v[1].n[2] - a -> v[0].n[2]*a -> v[1].n[1])/det; + b -> v[1].n[0] = c1/det; + b -> v[1].n[1] = (a -> v[0].n[0]*a -> v[2].n[2] - a -> v[0].n[2]*a -> v[2].n[0])/det; + b -> v[1].n[2] = (a -> v[0].n[2]*a -> v[1].n[0] - a -> v[0].n[0]*a -> v[1].n[2])/det; + b -> v[2].n[0] = c2/det; + b -> v[2].n[1] = (a -> v[0].n[1]*a -> v[2].n[0] - a -> v[0].n[0]*a -> v[2].n[1])/det; + b -> v[2].n[2] = (a -> v[0].n[0]*a -> v[1].n[1] - a -> v[0].n[1]*a -> v[1].n[0])/det; + + return TRUE; +} + + +// Solve a system in the form Ax = b +cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b) +{ + cmsMAT3 m, a_1; + + memmove(&m, a, sizeof(cmsMAT3)); + + if (!_cmsMAT3inverse(&m, &a_1)) return FALSE; // Singular matrix + + _cmsMAT3eval(x, &a_1, b); + return TRUE; +} + +// Evaluate a vector across a matrix +void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v) +{ + r->n[VX] = a->v[0].n[VX]*v->n[VX] + a->v[0].n[VY]*v->n[VY] + a->v[0].n[VZ]*v->n[VZ]; + r->n[VY] = a->v[1].n[VX]*v->n[VX] + a->v[1].n[VY]*v->n[VY] + a->v[1].n[VZ]*v->n[VZ]; + r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ]; +} + + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsnamed.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsnamed.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsnamed.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsnamed.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1009 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Multilocalized unicode objects. That is an attempt to encapsulate i18n. + + +// Allocates an empty multi localizad unicode object +cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems) +{ + cmsMLU* mlu; + + // nItems should be positive if given + if (nItems <= 0) nItems = 2; + + // Create the container + mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU)); + if (mlu == NULL) return NULL; + + mlu ->ContextID = ContextID; + + // Create entry array + mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry)); + if (mlu ->Entries == NULL) { + _cmsFree(ContextID, mlu); + return NULL; + } + + // Ok, keep indexes up to date + mlu ->AllocatedEntries = nItems; + mlu ->UsedEntries = 0; + + return mlu; +} + + +// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two. +static +cmsBool GrowMLUpool(cmsMLU* mlu) +{ + cmsUInt32Number size; + void *NewPtr; + + // Sanity check + if (mlu == NULL) return FALSE; + + if (mlu ->PoolSize == 0) + size = 256; + else + size = mlu ->PoolSize * 2; + + // Check for overflow + if (size < mlu ->PoolSize) return FALSE; + + // Reallocate the pool + NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size); + if (NewPtr == NULL) return FALSE; + + + mlu ->MemPool = NewPtr; + mlu ->PoolSize = size; + + return TRUE; +} + + +// Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two. +static +cmsBool GrowMLUtable(cmsMLU* mlu) +{ + cmsUInt32Number AllocatedEntries; + _cmsMLUentry *NewPtr; + + // Sanity check + if (mlu == NULL) return FALSE; + + AllocatedEntries = mlu ->AllocatedEntries * 2; + + // Check for overflow + if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE; + + // Reallocate the memory + NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry)); + if (NewPtr == NULL) return FALSE; + + mlu ->Entries = NewPtr; + mlu ->AllocatedEntries = AllocatedEntries; + + return TRUE; +} + + +// Search for a specific entry in the structure. Language and Country are used. +static +int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) +{ + cmsUInt32Number i; + + // Sanity check + if (mlu == NULL) return -1; + + // Iterate whole table + for (i=0; i < mlu ->UsedEntries; i++) { + + if (mlu ->Entries[i].Country == CountryCode && + mlu ->Entries[i].Language == LanguageCode) return (int) i; + } + + // Not found + return -1; +} + +// Add a block of characters to the intended MLU. Language and country are specified. +// Only one entry for Language/country pair is allowed. +static +cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, + cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) +{ + cmsUInt32Number Offset; + cmsUInt8Number* Ptr; + + // Sanity check + if (mlu == NULL) return FALSE; + + // Is there any room available? + if (mlu ->UsedEntries >= mlu ->AllocatedEntries) { + if (!GrowMLUtable(mlu)) return FALSE; + } + + // Only one ASCII string + if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed! + + // Check for size + while ((mlu ->PoolSize - mlu ->PoolUsed) < size) { + + if (!GrowMLUpool(mlu)) return FALSE; + } + + Offset = mlu ->PoolUsed; + + Ptr = (cmsUInt8Number*) mlu ->MemPool; + if (Ptr == NULL) return FALSE; + + // Set the entry + memmove(Ptr + Offset, Block, size); + mlu ->PoolUsed += size; + + mlu ->Entries[mlu ->UsedEntries].StrW = Offset; + mlu ->Entries[mlu ->UsedEntries].Len = size; + mlu ->Entries[mlu ->UsedEntries].Country = CountryCode; + mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode; + mlu ->UsedEntries++; + + return TRUE; +} + +// Convert from a 3-char code to a cmsUInt16Number. It is done in this way because some +// compilers don't properly align beginning of strings +static +cmsUInt16Number strTo16(const char str[3]) +{ + const cmsUInt8Number* ptr8; + cmsUInt16Number n; + + // For non-existent strings + if (str == NULL) return 0; + ptr8 = (const cmsUInt8Number*)str; + n = (cmsUInt16Number)(((cmsUInt16Number)ptr8[0] << 8) | ptr8[1]); + + return n; +} + +static +void strFrom16(char str[3], cmsUInt16Number n) +{ + str[0] = (char)(n >> 8); + str[1] = (char)n; + str[2] = (char)0; + +} + +// Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) +// In the case the user explicitely sets an empty string, we force a \0 +cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) +{ + cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString); + wchar_t* WStr; + cmsBool rc; + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); + + if (mlu == NULL) return FALSE; + + // len == 0 would prevent operation, so we set a empty string pointing to zero + if (len == 0) + { + len = 1; + } + + WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t)); + if (WStr == NULL) return FALSE; + + for (i=0; i < len; i++) + WStr[i] = (wchar_t) ASCIIString[i]; + + rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); + + _cmsFree(mlu ->ContextID, WStr); + return rc; + +} + +// We don't need any wcs support library +static +cmsUInt32Number mywcslen(const wchar_t *s) +{ + const wchar_t *p; + + p = s; + while (*p) + p++; + + return (cmsUInt32Number)(p - s); +} + +// Add a wide entry. Do not add any \0 terminator (ICC1v43_2010-12.pdf page 61) +cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString) +{ + cmsUInt16Number Lang = strTo16(Language); + cmsUInt16Number Cntry = strTo16(Country); + cmsUInt32Number len; + + if (mlu == NULL) return FALSE; + if (WideString == NULL) return FALSE; + + len = (cmsUInt32Number) (mywcslen(WideString)) * sizeof(wchar_t); + if (len == 0) + len = sizeof(wchar_t); + + return AddMLUBlock(mlu, len, WideString, Lang, Cntry); +} + +// Duplicating a MLU is as easy as copying all members +cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu) +{ + cmsMLU* NewMlu = NULL; + + // Duplicating a NULL obtains a NULL + if (mlu == NULL) return NULL; + + NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries); + if (NewMlu == NULL) return NULL; + + // Should never happen + if (NewMlu ->AllocatedEntries < mlu ->UsedEntries) + goto Error; + + // Sanitize... + if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error; + + memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry)); + NewMlu ->UsedEntries = mlu ->UsedEntries; + + // The MLU may be empty + if (mlu ->PoolUsed == 0) { + NewMlu ->MemPool = NULL; + } + else { + // It is not empty + NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed); + if (NewMlu ->MemPool == NULL) goto Error; + } + + NewMlu ->PoolSize = mlu ->PoolUsed; + + if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error; + + memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed); + NewMlu ->PoolUsed = mlu ->PoolUsed; + + return NewMlu; + +Error: + + if (NewMlu != NULL) cmsMLUfree(NewMlu); + return NULL; +} + +// Free any used memory +void CMSEXPORT cmsMLUfree(cmsMLU* mlu) +{ + if (mlu) { + + if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries); + if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool); + + _cmsFree(mlu ->ContextID, mlu); + } +} + + +// The algorithm first searches for an exact match of country and language, if not found it uses +// the Language. If none is found, first entry is used instead. +static +const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, + cmsUInt32Number *len, + cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode, + cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode) +{ + cmsUInt32Number i; + int Best = -1; + _cmsMLUentry* v; + + if (mlu == NULL) return NULL; + + if (mlu -> AllocatedEntries <= 0) return NULL; + + for (i=0; i < mlu ->UsedEntries; i++) { + + v = mlu ->Entries + i; + + if (v -> Language == LanguageCode) { + + if (Best == -1) Best = (int) i; + + if (v -> Country == CountryCode) { + + if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; + if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; + + if (len != NULL) *len = v ->Len; + + return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match + } + } + } + + // No string found. Return First one + if (Best == -1) + Best = 0; + + v = mlu ->Entries + Best; + + if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; + if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; + + if (len != NULL) *len = v ->Len; + + return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); +} + + +// Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len +cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) +{ + const wchar_t *Wide; + cmsUInt32Number StrLen = 0; + cmsUInt32Number ASCIIlen, i; + + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); + + // Sanitize + if (mlu == NULL) return 0; + + // Get WideChar + Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); + if (Wide == NULL) return 0; + + ASCIIlen = StrLen / sizeof(wchar_t); + + // Maybe we want only to know the len? + if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end + + // No buffer size means no data + if (BufferSize <= 0) return 0; + + // Some clipping may be required + if (BufferSize < ASCIIlen + 1) + ASCIIlen = BufferSize - 1; + + // Precess each character + for (i=0; i < ASCIIlen; i++) { + + if (Wide[i] == 0) + Buffer[i] = 0; + else + Buffer[i] = (char) Wide[i]; + } + + // We put a termination "\0" + Buffer[ASCIIlen] = 0; + return ASCIIlen + 1; +} + +// Obtain a wide representation of the MLU, on depending on current locale settings +cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize) +{ + const wchar_t *Wide; + cmsUInt32Number StrLen = 0; + + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); + + // Sanitize + if (mlu == NULL) return 0; + + Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); + if (Wide == NULL) return 0; + + // Maybe we want only to know the len? + if (Buffer == NULL) return StrLen + sizeof(wchar_t); + + // No buffer size means no data + if (BufferSize <= 0) return 0; + + // Some clipping may be required + if (BufferSize < StrLen + sizeof(wchar_t)) + StrLen = BufferSize - + sizeof(wchar_t); + + memmove(Buffer, Wide, StrLen); + Buffer[StrLen / sizeof(wchar_t)] = 0; + + return StrLen + sizeof(wchar_t); +} + + +// Get also the language and country +CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char ObtainedLanguage[3], char ObtainedCountry[3]) +{ + const wchar_t *Wide; + + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); + cmsUInt16Number ObtLang, ObtCode; + + // Sanitize + if (mlu == NULL) return FALSE; + + Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode); + if (Wide == NULL) return FALSE; + + // Get used language and code + strFrom16(ObtainedLanguage, ObtLang); + strFrom16(ObtainedCountry, ObtCode); + + return TRUE; +} + + + +// Get the number of translations in the MLU object +cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu) +{ + if (mlu == NULL) return 0; + return mlu->UsedEntries; +} + +// Get the language and country codes for a specific MLU index +cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, + cmsUInt32Number idx, + char LanguageCode[3], + char CountryCode[3]) +{ + _cmsMLUentry *entry; + + if (mlu == NULL) return FALSE; + + if (idx >= mlu->UsedEntries) return FALSE; + + entry = &mlu->Entries[idx]; + + strFrom16(LanguageCode, entry->Language); + strFrom16(CountryCode, entry->Country); + + return TRUE; +} + + +// Named color lists -------------------------------------------------------------------------------------------- + +// Grow the list to keep at least NumElements +static +cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) +{ + cmsUInt32Number size; + _cmsNAMEDCOLOR * NewPtr; + + if (v == NULL) return FALSE; + + if (v ->Allocated == 0) + size = 64; // Initial guess + else + size = v ->Allocated * 2; + + // Keep a maximum color lists can grow, 100K entries seems reasonable + if (size > 1024 * 100) { + _cmsFree(v->ContextID, (void*) v->List); + v->List = NULL; + return FALSE; + } + + NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR)); + if (NewPtr == NULL) + return FALSE; + + v ->List = NewPtr; + v ->Allocated = size; + return TRUE; +} + +// Allocate a list for n elements +cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix) +{ + cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST)); + + if (v == NULL) return NULL; + + v ->List = NULL; + v ->nColors = 0; + v ->ContextID = ContextID; + + while (v -> Allocated < n) { + if (!GrowNamedColorList(v)) { + cmsFreeNamedColorList(v); + return NULL; + } + } + + strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1); + strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1); + v->Prefix[32] = v->Suffix[32] = 0; + + v -> ColorantCount = ColorantCount; + + return v; +} + +// Free a list +void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v) +{ + if (v == NULL) return; + if (v ->List) _cmsFree(v ->ContextID, v ->List); + _cmsFree(v ->ContextID, v); +} + +cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) +{ + cmsNAMEDCOLORLIST* NewNC; + + if (v == NULL) return NULL; + + NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix); + if (NewNC == NULL) return NULL; + + // For really large tables we need this + while (NewNC ->Allocated < v ->Allocated){ + if (!GrowNamedColorList(NewNC)) + { + cmsFreeNamedColorList(NewNC); + return NULL; + } + } + + memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix)); + memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix)); + NewNC ->ColorantCount = v ->ColorantCount; + memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR)); + NewNC ->nColors = v ->nColors; + return NewNC; +} + + +// Append a color to a list. List pointer may change if reallocated +cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, + const char* Name, + cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS]) +{ + cmsUInt32Number i; + + if (NamedColorList == NULL) return FALSE; + + if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) { + if (!GrowNamedColorList(NamedColorList)) return FALSE; + } + + for (i=0; i < NamedColorList ->ColorantCount; i++) + NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL ? (cmsUInt16Number)0 : Colorant[i]; + + for (i=0; i < 3; i++) + NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? (cmsUInt16Number) 0 : PCS[i]; + + if (Name != NULL) { + + strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, cmsMAX_PATH-1); + NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0; + + } + else + NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0; + + + NamedColorList ->nColors++; + return TRUE; +} + +// Returns number of elements +cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList) +{ + if (NamedColorList == NULL) return 0; + return NamedColorList ->nColors; +} + +// Info aboout a given color +cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, + char* Name, + char* Prefix, + char* Suffix, + cmsUInt16Number* PCS, + cmsUInt16Number* Colorant) +{ + if (NamedColorList == NULL) return FALSE; + + if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE; + + // strcpy instead of strncpy because many apps are using small buffers + if (Name) strcpy(Name, NamedColorList->List[nColor].Name); + if (Prefix) strcpy(Prefix, NamedColorList->Prefix); + if (Suffix) strcpy(Suffix, NamedColorList->Suffix); + if (PCS) + memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number)); + + if (Colorant) + memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant, + sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount); + + + return TRUE; +} + +// Search for a given color name (no prefix or suffix) +cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name) +{ + cmsUInt32Number i; + cmsUInt32Number n; + + if (NamedColorList == NULL) return -1; + n = cmsNamedColorCount(NamedColorList); + for (i=0; i < n; i++) { + if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0) + return (cmsInt32Number) i; + } + + return -1; +} + +// MPE support ----------------------------------------------------------------------------------------------------------------- + +static +void FreeNamedColorList(cmsStage* mpe) +{ + cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; + cmsFreeNamedColorList(List); +} + +static +void* DupNamedColorList(cmsStage* mpe) +{ + cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; + return cmsDupNamedColorList(List); +} + +static +void EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; + cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); + + if (index >= NamedColorList-> nColors) { + cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range", index); + Out[0] = Out[1] = Out[2] = 0.0f; + } + else { + + // Named color always uses Lab + Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0); + Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0); + Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0); + } +} + +static +void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; + cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); + cmsUInt32Number j; + + if (index >= NamedColorList-> nColors) { + cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range", index); + for (j = 0; j < NamedColorList->ColorantCount; j++) + Out[j] = 0.0f; + + } + else { + for (j=0; j < NamedColorList ->ColorantCount; j++) + Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0); + } +} + + +// Named color lookup element +cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS) +{ + return _cmsStageAllocPlaceholder(NamedColorList ->ContextID, + cmsSigNamedColorElemType, + 1, UsePCS ? 3 : NamedColorList ->ColorantCount, + UsePCS ? EvalNamedColorPCS : EvalNamedColor, + DupNamedColorList, + FreeNamedColorList, + cmsDupNamedColorList(NamedColorList)); + +} + + +// Retrieve the named color list from a transform. Should be first element in the LUT +cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform) +{ + _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; + cmsStage* mpe = v ->Lut->Elements; + + if (mpe ->Type != cmsSigNamedColorElemType) return NULL; + return (cmsNAMEDCOLORLIST*) mpe ->Data; +} + + +// Profile sequence description routines ------------------------------------------------------------------------------------- + +cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n) +{ + cmsSEQ* Seq; + cmsUInt32Number i; + + if (n == 0) return NULL; + + // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked + // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door! + if (n > 255) return NULL; + + Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ)); + if (Seq == NULL) return NULL; + + Seq -> ContextID = ContextID; + Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC)); + Seq -> n = n; + + if (Seq -> seq == NULL) { + _cmsFree(ContextID, Seq); + return NULL; + } + + for (i=0; i < n; i++) { + Seq -> seq[i].Manufacturer = NULL; + Seq -> seq[i].Model = NULL; + Seq -> seq[i].Description = NULL; + } + + return Seq; +} + +void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq) +{ + cmsUInt32Number i; + + for (i=0; i < pseq ->n; i++) { + if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); + if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); + if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); + } + + if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq); + _cmsFree(pseq -> ContextID, pseq); +} + +cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq) +{ + cmsSEQ *NewSeq; + cmsUInt32Number i; + + if (pseq == NULL) + return NULL; + + NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ)); + if (NewSeq == NULL) return NULL; + + + NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC)); + if (NewSeq ->seq == NULL) goto Error; + + NewSeq -> ContextID = pseq ->ContextID; + NewSeq -> n = pseq ->n; + + for (i=0; i < pseq->n; i++) { + + memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number)); + + NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg; + NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel; + memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID)); + NewSeq ->seq[i].technology = pseq ->seq[i].technology; + + NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer); + NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model); + NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description); + + } + + return NewSeq; + +Error: + + cmsFreeProfileSequenceDescription(NewSeq); + return NULL; +} + +// Dictionaries -------------------------------------------------------------------------------------------------------- + +// Dictionaries are just very simple linked lists + + +typedef struct _cmsDICT_struct { + cmsDICTentry* head; + cmsContext ContextID; +} _cmsDICT; + + +// Allocate an empty dictionary +cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID) +{ + _cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT)); + if (dict == NULL) return NULL; + + dict ->ContextID = ContextID; + return (cmsHANDLE) dict; + +} + +// Dispose resources +void CMSEXPORT cmsDictFree(cmsHANDLE hDict) +{ + _cmsDICT* dict = (_cmsDICT*) hDict; + cmsDICTentry *entry, *next; + + _cmsAssert(dict != NULL); + + // Walk the list freeing all nodes + entry = dict ->head; + while (entry != NULL) { + + if (entry ->DisplayName != NULL) cmsMLUfree(entry ->DisplayName); + if (entry ->DisplayValue != NULL) cmsMLUfree(entry ->DisplayValue); + if (entry ->Name != NULL) _cmsFree(dict ->ContextID, entry -> Name); + if (entry ->Value != NULL) _cmsFree(dict ->ContextID, entry -> Value); + + // Don't fall in the habitual trap... + next = entry ->Next; + _cmsFree(dict ->ContextID, entry); + + entry = next; + } + + _cmsFree(dict ->ContextID, dict); +} + + +// Duplicate a wide char string +static +wchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr) +{ + if (ptr == NULL) return NULL; + return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t)); +} + +// Add a new entry to the linked list +cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue) +{ + _cmsDICT* dict = (_cmsDICT*) hDict; + cmsDICTentry *entry; + + _cmsAssert(dict != NULL); + _cmsAssert(Name != NULL); + + entry = (cmsDICTentry*) _cmsMallocZero(dict ->ContextID, sizeof(cmsDICTentry)); + if (entry == NULL) return FALSE; + + entry ->DisplayName = cmsMLUdup(DisplayName); + entry ->DisplayValue = cmsMLUdup(DisplayValue); + entry ->Name = DupWcs(dict ->ContextID, Name); + entry ->Value = DupWcs(dict ->ContextID, Value); + + entry ->Next = dict ->head; + dict ->head = entry; + + return TRUE; +} + + +// Duplicates an existing dictionary +cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict) +{ + _cmsDICT* old_dict = (_cmsDICT*) hDict; + cmsHANDLE hNew; + cmsDICTentry *entry; + + _cmsAssert(old_dict != NULL); + + hNew = cmsDictAlloc(old_dict ->ContextID); + if (hNew == NULL) return NULL; + + // Walk the list freeing all nodes + entry = old_dict ->head; + while (entry != NULL) { + + if (!cmsDictAddEntry(hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) { + + cmsDictFree(hNew); + return NULL; + } + + entry = entry -> Next; + } + + return hNew; +} + +// Get a pointer to the linked list +const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict) +{ + _cmsDICT* dict = (_cmsDICT*) hDict; + + if (dict == NULL) return NULL; + return dict ->head; +} + +// Helper For external languages +const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e) +{ + if (e == NULL) return NULL; + return e ->Next; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsopt.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsopt.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsopt.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsopt.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,2005 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +//---------------------------------------------------------------------------------- + +// Optimization for 8 bits, Shaper-CLUT (3 inputs only) +typedef struct { + + cmsContext ContextID; + + const cmsInterpParams* p; // Tetrahedrical interpolation parameters. This is a not-owned pointer. + + cmsUInt16Number rx[256], ry[256], rz[256]; + cmsUInt32Number X0[256], Y0[256], Z0[256]; // Precomputed nodes and offsets for 8-bit input data + + +} Prelin8Data; + + +// Generic optimization for 16 bits Shaper-CLUT-Shaper (any inputs) +typedef struct { + + cmsContext ContextID; + + // Number of channels + cmsUInt32Number nInputs; + cmsUInt32Number nOutputs; + + _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance + cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS]; + + _cmsInterpFn16 EvalCLUT; // The evaluator for 3D grid + const cmsInterpParams* CLUTparams; // (not-owned pointer) + + + _cmsInterpFn16* EvalCurveOut16; // Points to an array of curve evaluators in 16 bits (not-owned pointer) + cmsInterpParams** ParamsCurveOut16; // Points to an array of references to interpolation params (not-owned pointer) + + +} Prelin16Data; + + +// Optimization for matrix-shaper in 8 bits. Numbers are operated in n.14 signed, tables are stored in 1.14 fixed + +typedef cmsInt32Number cmsS1Fixed14Number; // Note that this may hold more than 16 bits! + +#define DOUBLE_TO_1FIXED14(x) ((cmsS1Fixed14Number) floor((x) * 16384.0 + 0.5)) + +typedef struct { + + cmsContext ContextID; + + cmsS1Fixed14Number Shaper1R[256]; // from 0..255 to 1.14 (0.0...1.0) + cmsS1Fixed14Number Shaper1G[256]; + cmsS1Fixed14Number Shaper1B[256]; + + cmsS1Fixed14Number Mat[3][3]; // n.14 to n.14 (needs a saturation after that) + cmsS1Fixed14Number Off[3]; + + cmsUInt16Number Shaper2R[16385]; // 1.14 to 0..255 + cmsUInt16Number Shaper2G[16385]; + cmsUInt16Number Shaper2B[16385]; + +} MatShaper8Data; + +// Curves, optimization is shared between 8 and 16 bits +typedef struct { + + cmsContext ContextID; + + cmsUInt32Number nCurves; // Number of curves + cmsUInt32Number nElements; // Elements in curves + cmsUInt16Number** Curves; // Points to a dynamically allocated array + +} Curves16Data; + + +// Simple optimizations ---------------------------------------------------------------------------------------------------------- + + +// Remove an element in linked chain +static +void _RemoveElement(cmsStage** head) +{ + cmsStage* mpe = *head; + cmsStage* next = mpe ->Next; + *head = next; + cmsStageFree(mpe); +} + +// Remove all identities in chain. Note that pt actually is a double pointer to the element that holds the pointer. +static +cmsBool _Remove1Op(cmsPipeline* Lut, cmsStageSignature UnaryOp) +{ + cmsStage** pt = &Lut ->Elements; + cmsBool AnyOpt = FALSE; + + while (*pt != NULL) { + + if ((*pt) ->Implements == UnaryOp) { + _RemoveElement(pt); + AnyOpt = TRUE; + } + else + pt = &((*pt) -> Next); + } + + return AnyOpt; +} + +// Same, but only if two adjacent elements are found +static +cmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op2) +{ + cmsStage** pt1; + cmsStage** pt2; + cmsBool AnyOpt = FALSE; + + pt1 = &Lut ->Elements; + if (*pt1 == NULL) return AnyOpt; + + while (*pt1 != NULL) { + + pt2 = &((*pt1) -> Next); + if (*pt2 == NULL) return AnyOpt; + + if ((*pt1) ->Implements == Op1 && (*pt2) ->Implements == Op2) { + _RemoveElement(pt2); + _RemoveElement(pt1); + AnyOpt = TRUE; + } + else + pt1 = &((*pt1) -> Next); + } + + return AnyOpt; +} + + +static +cmsBool CloseEnoughFloat(cmsFloat64Number a, cmsFloat64Number b) +{ + return fabs(b - a) < 0.00001f; +} + +static +cmsBool isFloatMatrixIdentity(const cmsMAT3* a) +{ + cmsMAT3 Identity; + int i, j; + + _cmsMAT3identity(&Identity); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if (!CloseEnoughFloat(a->v[i].n[j], Identity.v[i].n[j])) return FALSE; + + return TRUE; +} +// if two adjacent matrices are found, multiply them. +static +cmsBool _MultiplyMatrix(cmsPipeline* Lut) +{ + cmsStage** pt1; + cmsStage** pt2; + cmsStage* chain; + cmsBool AnyOpt = FALSE; + + pt1 = &Lut->Elements; + if (*pt1 == NULL) return AnyOpt; + + while (*pt1 != NULL) { + + pt2 = &((*pt1)->Next); + if (*pt2 == NULL) return AnyOpt; + + if ((*pt1)->Implements == cmsSigMatrixElemType && (*pt2)->Implements == cmsSigMatrixElemType) { + + // Get both matrices + _cmsStageMatrixData* m1 = (_cmsStageMatrixData*) cmsStageData(*pt1); + _cmsStageMatrixData* m2 = (_cmsStageMatrixData*) cmsStageData(*pt2); + cmsMAT3 res; + + // Input offset and output offset should be zero to use this optimization + if (m1->Offset != NULL || m2 ->Offset != NULL || + cmsStageInputChannels(*pt1) != 3 || cmsStageOutputChannels(*pt1) != 3 || + cmsStageInputChannels(*pt2) != 3 || cmsStageOutputChannels(*pt2) != 3) + return FALSE; + + // Multiply both matrices to get the result + _cmsMAT3per(&res, (cmsMAT3*)m2->Double, (cmsMAT3*)m1->Double); + + // Get the next in chain after the matrices + chain = (*pt2)->Next; + + // Remove both matrices + _RemoveElement(pt2); + _RemoveElement(pt1); + + // Now what if the result is a plain identity? + if (!isFloatMatrixIdentity(&res)) { + + // We can not get rid of full matrix + cmsStage* Multmat = cmsStageAllocMatrix(Lut->ContextID, 3, 3, (const cmsFloat64Number*) &res, NULL); + if (Multmat == NULL) return FALSE; // Should never happen + + // Recover the chain + Multmat->Next = chain; + *pt1 = Multmat; + } + + AnyOpt = TRUE; + } + else + pt1 = &((*pt1)->Next); + } + + return AnyOpt; +} + + +// Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed +// by a v4 to v2 and vice-versa. The elements are then discarded. +static +cmsBool PreOptimize(cmsPipeline* Lut) +{ + cmsBool AnyOpt = FALSE, Opt; + + do { + + Opt = FALSE; + + // Remove all identities + Opt |= _Remove1Op(Lut, cmsSigIdentityElemType); + + // Remove XYZ2Lab followed by Lab2XYZ + Opt |= _Remove2Op(Lut, cmsSigXYZ2LabElemType, cmsSigLab2XYZElemType); + + // Remove Lab2XYZ followed by XYZ2Lab + Opt |= _Remove2Op(Lut, cmsSigLab2XYZElemType, cmsSigXYZ2LabElemType); + + // Remove V4 to V2 followed by V2 to V4 + Opt |= _Remove2Op(Lut, cmsSigLabV4toV2, cmsSigLabV2toV4); + + // Remove V2 to V4 followed by V4 to V2 + Opt |= _Remove2Op(Lut, cmsSigLabV2toV4, cmsSigLabV4toV2); + + // Remove float pcs Lab conversions + Opt |= _Remove2Op(Lut, cmsSigLab2FloatPCS, cmsSigFloatPCS2Lab); + + // Remove float pcs Lab conversions + Opt |= _Remove2Op(Lut, cmsSigXYZ2FloatPCS, cmsSigFloatPCS2XYZ); + + // Simplify matrix. + Opt |= _MultiplyMatrix(Lut); + + if (Opt) AnyOpt = TRUE; + + } while (Opt); + + return AnyOpt; +} + +static +void Eval16nop1D(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const struct _cms_interp_struc* p) +{ + Output[0] = Input[0]; + + cmsUNUSED_PARAMETER(p); +} + +static +void PrelinEval16(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const void* D) +{ + Prelin16Data* p16 = (Prelin16Data*) D; + cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS]; + cmsUInt16Number StageDEF[cmsMAXCHANNELS]; + cmsUInt32Number i; + + for (i=0; i < p16 ->nInputs; i++) { + + p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]); + } + + p16 ->EvalCLUT(StageABC, StageDEF, p16 ->CLUTparams); + + for (i=0; i < p16 ->nOutputs; i++) { + + p16 ->EvalCurveOut16[i](&StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); + } +} + + +static +void PrelinOpt16free(cmsContext ContextID, void* ptr) +{ + Prelin16Data* p16 = (Prelin16Data*) ptr; + + _cmsFree(ContextID, p16 ->EvalCurveOut16); + _cmsFree(ContextID, p16 ->ParamsCurveOut16); + + _cmsFree(ContextID, p16); +} + +static +void* Prelin16dup(cmsContext ContextID, const void* ptr) +{ + Prelin16Data* p16 = (Prelin16Data*) ptr; + Prelin16Data* Duped = (Prelin16Data*) _cmsDupMem(ContextID, p16, sizeof(Prelin16Data)); + + if (Duped == NULL) return NULL; + + Duped->EvalCurveOut16 = (_cmsInterpFn16*) _cmsDupMem(ContextID, p16->EvalCurveOut16, p16->nOutputs * sizeof(_cmsInterpFn16)); + Duped->ParamsCurveOut16 = (cmsInterpParams**)_cmsDupMem(ContextID, p16->ParamsCurveOut16, p16->nOutputs * sizeof(cmsInterpParams*)); + + return Duped; +} + + +static +Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, + const cmsInterpParams* ColorMap, + cmsUInt32Number nInputs, cmsToneCurve** In, + cmsUInt32Number nOutputs, cmsToneCurve** Out ) +{ + cmsUInt32Number i; + Prelin16Data* p16 = (Prelin16Data*)_cmsMallocZero(ContextID, sizeof(Prelin16Data)); + if (p16 == NULL) return NULL; + + p16 ->nInputs = nInputs; + p16 ->nOutputs = nOutputs; + + + for (i=0; i < nInputs; i++) { + + if (In == NULL) { + p16 -> ParamsCurveIn16[i] = NULL; + p16 -> EvalCurveIn16[i] = Eval16nop1D; + + } + else { + p16 -> ParamsCurveIn16[i] = In[i] ->InterpParams; + p16 -> EvalCurveIn16[i] = p16 ->ParamsCurveIn16[i]->Interpolation.Lerp16; + } + } + + p16 ->CLUTparams = ColorMap; + p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16; + + + p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16)); + if (p16->EvalCurveOut16 == NULL) + { + _cmsFree(ContextID, p16); + return NULL; + } + + p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* )); + if (p16->ParamsCurveOut16 == NULL) + { + + _cmsFree(ContextID, p16->EvalCurveOut16); + _cmsFree(ContextID, p16); + return NULL; + } + + for (i=0; i < nOutputs; i++) { + + if (Out == NULL) { + p16 ->ParamsCurveOut16[i] = NULL; + p16 -> EvalCurveOut16[i] = Eval16nop1D; + } + else { + + p16 ->ParamsCurveOut16[i] = Out[i] ->InterpParams; + p16 -> EvalCurveOut16[i] = p16 ->ParamsCurveOut16[i]->Interpolation.Lerp16; + } + } + + return p16; +} + + + +// Resampling --------------------------------------------------------------------------------- + +#define PRELINEARIZATION_POINTS 4096 + +// Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for +// almost any transform. We use floating point precision and then convert from floating point to 16 bits. +static +cmsInt32Number XFormSampler16(CMSREGISTER const cmsUInt16Number In[], + CMSREGISTER cmsUInt16Number Out[], + CMSREGISTER void* Cargo) +{ + cmsPipeline* Lut = (cmsPipeline*) Cargo; + cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; + cmsUInt32Number i; + + _cmsAssert(Lut -> InputChannels < cmsMAXCHANNELS); + _cmsAssert(Lut -> OutputChannels < cmsMAXCHANNELS); + + // From 16 bit to floating point + for (i=0; i < Lut ->InputChannels; i++) + InFloat[i] = (cmsFloat32Number) (In[i] / 65535.0); + + // Evaluate in floating point + cmsPipelineEvalFloat(InFloat, OutFloat, Lut); + + // Back to 16 bits representation + for (i=0; i < Lut ->OutputChannels; i++) + Out[i] = _cmsQuickSaturateWord(OutFloat[i] * 65535.0); + + // Always succeed + return TRUE; +} + +// Try to see if the curves of a given MPE are linear +static +cmsBool AllCurvesAreLinear(cmsStage* mpe) +{ + cmsToneCurve** Curves; + cmsUInt32Number i, n; + + Curves = _cmsStageGetPtrToCurveSet(mpe); + if (Curves == NULL) return FALSE; + + n = cmsStageOutputChannels(mpe); + + for (i=0; i < n; i++) { + if (!cmsIsToneCurveLinear(Curves[i])) return FALSE; + } + + return TRUE; +} + +// This function replaces a specific node placed in "At" by the "Value" numbers. Its purpose +// is to fix scum dot on broken profiles/transforms. Works on 1, 3 and 4 channels +static +cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], + cmsUInt32Number nChannelsOut, cmsUInt32Number nChannelsIn) +{ + _cmsStageCLutData* Grid = (_cmsStageCLutData*) CLUT ->Data; + cmsInterpParams* p16 = Grid ->Params; + cmsFloat64Number px, py, pz, pw; + int x0, y0, z0, w0; + int i, index; + + if (CLUT -> Type != cmsSigCLutElemType) { + cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut stage"); + return FALSE; + } + + if (nChannelsIn == 4) { + + px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; + py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; + pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; + pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0; + + x0 = (int) floor(px); + y0 = (int) floor(py); + z0 = (int) floor(pz); + w0 = (int) floor(pw); + + if (((px - x0) != 0) || + ((py - y0) != 0) || + ((pz - z0) != 0) || + ((pw - w0) != 0)) return FALSE; // Not on exact node + + index = (int) p16 -> opta[3] * x0 + + (int) p16 -> opta[2] * y0 + + (int) p16 -> opta[1] * z0 + + (int) p16 -> opta[0] * w0; + } + else + if (nChannelsIn == 3) { + + px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; + py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; + pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; + + x0 = (int) floor(px); + y0 = (int) floor(py); + z0 = (int) floor(pz); + + if (((px - x0) != 0) || + ((py - y0) != 0) || + ((pz - z0) != 0)) return FALSE; // Not on exact node + + index = (int) p16 -> opta[2] * x0 + + (int) p16 -> opta[1] * y0 + + (int) p16 -> opta[0] * z0; + } + else + if (nChannelsIn == 1) { + + px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; + + x0 = (int) floor(px); + + if (((px - x0) != 0)) return FALSE; // Not on exact node + + index = (int) p16 -> opta[0] * x0; + } + else { + cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); + return FALSE; + } + + for (i = 0; i < (int) nChannelsOut; i++) + Grid->Tab.T[index + i] = Value[i]; + + return TRUE; +} + +// Auxiliary, to see if two values are equal or very different +static +cmsBool WhitesAreEqual(cmsUInt32Number n, cmsUInt16Number White1[], cmsUInt16Number White2[] ) +{ + cmsUInt32Number i; + + for (i=0; i < n; i++) { + + if (abs(White1[i] - White2[i]) > 0xf000) return TRUE; // Values are so extremely different that the fixup should be avoided + if (White1[i] != White2[i]) return FALSE; + } + return TRUE; +} + + +// Locate the node for the white point and fix it to pure white in order to avoid scum dot. +static +cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColorSpace, cmsColorSpaceSignature ExitColorSpace) +{ + cmsUInt16Number *WhitePointIn, *WhitePointOut; + cmsUInt16Number WhiteIn[cmsMAXCHANNELS], WhiteOut[cmsMAXCHANNELS], ObtainedOut[cmsMAXCHANNELS]; + cmsUInt32Number i, nOuts, nIns; + cmsStage *PreLin = NULL, *CLUT = NULL, *PostLin = NULL; + + if (!_cmsEndPointsBySpace(EntryColorSpace, + &WhitePointIn, NULL, &nIns)) return FALSE; + + if (!_cmsEndPointsBySpace(ExitColorSpace, + &WhitePointOut, NULL, &nOuts)) return FALSE; + + // It needs to be fixed? + if (Lut ->InputChannels != nIns) return FALSE; + if (Lut ->OutputChannels != nOuts) return FALSE; + + cmsPipelineEval16(WhitePointIn, ObtainedOut, Lut); + + if (WhitesAreEqual(nOuts, WhitePointOut, ObtainedOut)) return TRUE; // whites already match + + // Check if the LUT comes as Prelin, CLUT or Postlin. We allow all combinations + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &PreLin, &CLUT, &PostLin)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCurveSetElemType, cmsSigCLutElemType, &PreLin, &CLUT)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCLutElemType, cmsSigCurveSetElemType, &CLUT, &PostLin)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCLutElemType, &CLUT)) + return FALSE; + + // We need to interpolate white points of both, pre and post curves + if (PreLin) { + + cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PreLin); + + for (i=0; i < nIns; i++) { + WhiteIn[i] = cmsEvalToneCurve16(Curves[i], WhitePointIn[i]); + } + } + else { + for (i=0; i < nIns; i++) + WhiteIn[i] = WhitePointIn[i]; + } + + // If any post-linearization, we need to find how is represented white before the curve, do + // a reverse interpolation in this case. + if (PostLin) { + + cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PostLin); + + for (i=0; i < nOuts; i++) { + + cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]); + if (InversePostLin == NULL) { + WhiteOut[i] = WhitePointOut[i]; + + } else { + + WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); + cmsFreeToneCurve(InversePostLin); + } + } + } + else { + for (i=0; i < nOuts; i++) + WhiteOut[i] = WhitePointOut[i]; + } + + // Ok, proceed with patching. May fail and we don't care if it fails + PatchLUT(CLUT, WhiteIn, WhiteOut, nOuts, nIns); + + return TRUE; +} + +// ----------------------------------------------------------------------------------------------------------------------------------------------- +// This function creates simple LUT from complex ones. The generated LUT has an optional set of +// prelinearization curves, a CLUT of nGridPoints and optional postlinearization tables. +// These curves have to exist in the original LUT in order to be used in the simplified output. +// Caller may also use the flags to allow this feature. +// LUTS with all curves will be simplified to a single curve. Parametric curves are lost. +// This function should be used on 16-bits LUTS only, as floating point losses precision when simplified +// ----------------------------------------------------------------------------------------------------------------------------------------------- + +static +cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + cmsPipeline* Src = NULL; + cmsPipeline* Dest = NULL; + cmsStage* mpe; + cmsStage* CLUT; + cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; + cmsUInt32Number nGridPoints; + cmsColorSpaceSignature ColorSpace, OutputColorSpace; + cmsStage *NewPreLin = NULL; + cmsStage *NewPostLin = NULL; + _cmsStageCLutData* DataCLUT; + cmsToneCurve** DataSetIn; + cmsToneCurve** DataSetOut; + Prelin16Data* p16; + + // This is a lossy optimization! does not apply in floating-point cases + if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; + + ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat)); + OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat)); + + // Color space must be specified + if (ColorSpace == (cmsColorSpaceSignature)0 || + OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE; + + nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); + + // For empty LUTs, 2 points are enough + if (cmsPipelineStageCount(*Lut) == 0) + nGridPoints = 2; + + Src = *Lut; + + // Named color pipelines cannot be optimized either + for (mpe = cmsPipelineGetPtrToFirstStage(Src); + mpe != NULL; + mpe = cmsStageNext(mpe)) { + if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; + } + + // Allocate an empty LUT + Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); + if (!Dest) return FALSE; + + // Prelinearization tables are kept unless indicated by flags + if (*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION) { + + // Get a pointer to the prelinearization element + cmsStage* PreLin = cmsPipelineGetPtrToFirstStage(Src); + + // Check if suitable + if (PreLin && PreLin ->Type == cmsSigCurveSetElemType) { + + // Maybe this is a linear tram, so we can avoid the whole stuff + if (!AllCurvesAreLinear(PreLin)) { + + // All seems ok, proceed. + NewPreLin = cmsStageDup(PreLin); + if(!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin)) + goto Error; + + // Remove prelinearization. Since we have duplicated the curve + // in destination LUT, the sampling should be applied after this stage. + cmsPipelineUnlinkStage(Src, cmsAT_BEGIN, &KeepPreLin); + } + } + } + + // Allocate the CLUT + CLUT = cmsStageAllocCLut16bit(Src ->ContextID, nGridPoints, Src ->InputChannels, Src->OutputChannels, NULL); + if (CLUT == NULL) goto Error; + + // Add the CLUT to the destination LUT + if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) { + goto Error; + } + + // Postlinearization tables are kept unless indicated by flags + if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) { + + // Get a pointer to the postlinearization if present + cmsStage* PostLin = cmsPipelineGetPtrToLastStage(Src); + + // Check if suitable + if (PostLin && cmsStageType(PostLin) == cmsSigCurveSetElemType) { + + // Maybe this is a linear tram, so we can avoid the whole stuff + if (!AllCurvesAreLinear(PostLin)) { + + // All seems ok, proceed. + NewPostLin = cmsStageDup(PostLin); + if (!cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin)) + goto Error; + + // In destination LUT, the sampling should be applied after this stage. + cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin); + } + } + } + + // Now its time to do the sampling. We have to ignore pre/post linearization + // The source LUT without pre/post curves is passed as parameter. + if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) { +Error: + // Ops, something went wrong, Restore stages + if (KeepPreLin != NULL) { + if (!cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin)) { + _cmsAssert(0); // This never happens + } + } + if (KeepPostLin != NULL) { + if (!cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin)) { + _cmsAssert(0); // This never happens + } + } + cmsPipelineFree(Dest); + return FALSE; + } + + // Done. + + if (KeepPreLin != NULL) cmsStageFree(KeepPreLin); + if (KeepPostLin != NULL) cmsStageFree(KeepPostLin); + cmsPipelineFree(Src); + + DataCLUT = (_cmsStageCLutData*) CLUT ->Data; + + if (NewPreLin == NULL) DataSetIn = NULL; + else DataSetIn = ((_cmsStageToneCurvesData*) NewPreLin ->Data) ->TheCurves; + + if (NewPostLin == NULL) DataSetOut = NULL; + else DataSetOut = ((_cmsStageToneCurvesData*) NewPostLin ->Data) ->TheCurves; + + + if (DataSetIn == NULL && DataSetOut == NULL) { + + _cmsPipelineSetOptimizationParameters(Dest, (_cmsPipelineEval16Fn) DataCLUT->Params->Interpolation.Lerp16, DataCLUT->Params, NULL, NULL); + } + else { + + p16 = PrelinOpt16alloc(Dest ->ContextID, + DataCLUT ->Params, + Dest ->InputChannels, + DataSetIn, + Dest ->OutputChannels, + DataSetOut); + + _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); + } + + + // Don't fix white on absolute colorimetric + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) + *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; + + if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) { + + FixWhiteMisalignment(Dest, ColorSpace, OutputColorSpace); + } + + *Lut = Dest; + return TRUE; + + cmsUNUSED_PARAMETER(Intent); +} + + +// ----------------------------------------------------------------------------------------------------------------------------------------------- +// Fixes the gamma balancing of transform. This is described in my paper "Prelinearization Stages on +// Color-Management Application-Specific Integrated Circuits (ASICs)" presented at NIP24. It only works +// for RGB transforms. See the paper for more details +// ----------------------------------------------------------------------------------------------------------------------------------------------- + + +// Normalize endpoints by slope limiting max and min. This assures endpoints as well. +// Descending curves are handled as well. +static +void SlopeLimiting(cmsToneCurve* g) +{ + int BeginVal, EndVal; + int AtBegin = (int) floor((cmsFloat64Number) g ->nEntries * 0.02 + 0.5); // Cutoff at 2% + int AtEnd = (int) g ->nEntries - AtBegin - 1; // And 98% + cmsFloat64Number Val, Slope, beta; + int i; + + if (cmsIsToneCurveDescending(g)) { + BeginVal = 0xffff; EndVal = 0; + } + else { + BeginVal = 0; EndVal = 0xffff; + } + + // Compute slope and offset for begin of curve + Val = g ->Table16[AtBegin]; + Slope = (Val - BeginVal) / AtBegin; + beta = Val - Slope * AtBegin; + + for (i=0; i < AtBegin; i++) + g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); + + // Compute slope and offset for the end + Val = g ->Table16[AtEnd]; + Slope = (EndVal - Val) / AtBegin; // AtBegin holds the X interval, which is same in both cases + beta = Val - Slope * AtEnd; + + for (i = AtEnd; i < (int) g ->nEntries; i++) + g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); +} + + +// Precomputes tables for 8-bit on input devicelink. +static +Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cmsToneCurve* G[3]) +{ + int i; + cmsUInt16Number Input[3]; + cmsS15Fixed16Number v1, v2, v3; + Prelin8Data* p8; + + p8 = (Prelin8Data*)_cmsMallocZero(ContextID, sizeof(Prelin8Data)); + if (p8 == NULL) return NULL; + + // Since this only works for 8 bit input, values comes always as x * 257, + // we can safely take msb byte (x << 8 + x) + + for (i=0; i < 256; i++) { + + if (G != NULL) { + + // Get 16-bit representation + Input[0] = cmsEvalToneCurve16(G[0], FROM_8_TO_16(i)); + Input[1] = cmsEvalToneCurve16(G[1], FROM_8_TO_16(i)); + Input[2] = cmsEvalToneCurve16(G[2], FROM_8_TO_16(i)); + } + else { + Input[0] = FROM_8_TO_16(i); + Input[1] = FROM_8_TO_16(i); + Input[2] = FROM_8_TO_16(i); + } + + + // Move to 0..1.0 in fixed domain + v1 = _cmsToFixedDomain((int) (Input[0] * p -> Domain[0])); + v2 = _cmsToFixedDomain((int) (Input[1] * p -> Domain[1])); + v3 = _cmsToFixedDomain((int) (Input[2] * p -> Domain[2])); + + // Store the precalculated table of nodes + p8 ->X0[i] = (p->opta[2] * FIXED_TO_INT(v1)); + p8 ->Y0[i] = (p->opta[1] * FIXED_TO_INT(v2)); + p8 ->Z0[i] = (p->opta[0] * FIXED_TO_INT(v3)); + + // Store the precalculated table of offsets + p8 ->rx[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v1); + p8 ->ry[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v2); + p8 ->rz[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v3); + } + + p8 ->ContextID = ContextID; + p8 ->p = p; + + return p8; +} + +static +void Prelin8free(cmsContext ContextID, void* ptr) +{ + _cmsFree(ContextID, ptr); +} + +static +void* Prelin8dup(cmsContext ContextID, const void* ptr) +{ + return _cmsDupMem(ContextID, ptr, sizeof(Prelin8Data)); +} + + + +// A optimized interpolation for 8-bit input. +#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) +static CMS_NO_SANITIZE +void PrelinEval8(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const void* D) +{ + + cmsUInt8Number r, g, b; + cmsS15Fixed16Number rx, ry, rz; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + int OutChan; + CMSREGISTER cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; + Prelin8Data* p8 = (Prelin8Data*) D; + CMSREGISTER const cmsInterpParams* p = p8 ->p; + int TotalOut = (int) p -> nOutputs; + const cmsUInt16Number* LutTable = (const cmsUInt16Number*) p->Table; + + r = (cmsUInt8Number) (Input[0] >> 8); + g = (cmsUInt8Number) (Input[1] >> 8); + b = (cmsUInt8Number) (Input[2] >> 8); + + X0 = (cmsS15Fixed16Number) p8->X0[r]; + Y0 = (cmsS15Fixed16Number) p8->Y0[g]; + Z0 = (cmsS15Fixed16Number) p8->Z0[b]; + + rx = p8 ->rx[r]; + ry = p8 ->ry[g]; + rz = p8 ->rz[b]; + + X1 = X0 + (cmsS15Fixed16Number)((rx == 0) ? 0 : p ->opta[2]); + Y1 = Y0 + (cmsS15Fixed16Number)((ry == 0) ? 0 : p ->opta[1]); + Z1 = Z0 + (cmsS15Fixed16Number)((rz == 0) ? 0 : p ->opta[0]); + + + // These are the 6 Tetrahedral + for (OutChan=0; OutChan < TotalOut; OutChan++) { + + c0 = DENS(X0, Y0, Z0); + + if (rx >= ry && ry >= rz) + { + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + } + else + if (rx >= rz && rz >= ry) + { + c1 = DENS(X1, Y0, Z0) - c0; + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); + } + else + if (rz >= rx && rx >= ry) + { + c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); + c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + } + else + if (ry >= rx && rx >= rz) + { + c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); + } + else + if (ry >= rz && rz >= rx) + { + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z0) - c0; + c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); + } + else + if (rz >= ry && ry >= rx) + { + c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); + c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); + c3 = DENS(X0, Y0, Z1) - c0; + } + else { + c1 = c2 = c3 = 0; + } + + Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; + Output[OutChan] = (cmsUInt16Number) (c0 + ((Rest + (Rest >> 16)) >> 16)); + + } +} + +#undef DENS + + +// Curves that contain wide empty areas are not optimizeable +static +cmsBool IsDegenerated(const cmsToneCurve* g) +{ + cmsUInt32Number i, Zeros = 0, Poles = 0; + cmsUInt32Number nEntries = g ->nEntries; + + for (i=0; i < nEntries; i++) { + + if (g ->Table16[i] == 0x0000) Zeros++; + if (g ->Table16[i] == 0xffff) Poles++; + } + + if (Zeros == 1 && Poles == 1) return FALSE; // For linear tables + if (Zeros > (nEntries / 20)) return TRUE; // Degenerated, many zeros + if (Poles > (nEntries / 20)) return TRUE; // Degenerated, many poles + + return FALSE; +} + +// -------------------------------------------------------------------------------------------------------------- +// We need xput over here + +static +cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + cmsPipeline* OriginalLut; + cmsUInt32Number nGridPoints; + cmsToneCurve *Trans[cmsMAXCHANNELS], *TransReverse[cmsMAXCHANNELS]; + cmsUInt32Number t, i; + cmsFloat32Number v, In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS]; + cmsBool lIsSuitable, lIsLinear; + cmsPipeline* OptimizedLUT = NULL, *LutPlusCurves = NULL; + cmsStage* OptimizedCLUTmpe; + cmsColorSpaceSignature ColorSpace, OutputColorSpace; + cmsStage* OptimizedPrelinMpe; + cmsStage* mpe; + cmsToneCurve** OptimizedPrelinCurves; + _cmsStageCLutData* OptimizedPrelinCLUT; + + + // This is a lossy optimization! does not apply in floating-point cases + if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; + + // Only on chunky RGB + if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE; + if (T_PLANAR(*InputFormat)) return FALSE; + + if (T_COLORSPACE(*OutputFormat) != PT_RGB) return FALSE; + if (T_PLANAR(*OutputFormat)) return FALSE; + + // On 16 bits, user has to specify the feature + if (!_cmsFormatterIs8bit(*InputFormat)) { + if (!(*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION)) return FALSE; + } + + OriginalLut = *Lut; + + // Named color pipelines cannot be optimized either + for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut); + mpe != NULL; + mpe = cmsStageNext(mpe)) { + if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; + } + + ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat)); + OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat)); + + // Color space must be specified + if (ColorSpace == (cmsColorSpaceSignature)0 || + OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE; + + nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); + + // Empty gamma containers + memset(Trans, 0, sizeof(Trans)); + memset(TransReverse, 0, sizeof(TransReverse)); + + // If the last stage of the original lut are curves, and those curves are + // degenerated, it is likely the transform is squeezing and clipping + // the output from previous CLUT. We cannot optimize this case + { + cmsStage* last = cmsPipelineGetPtrToLastStage(OriginalLut); + + if (last == NULL) goto Error; + if (cmsStageType(last) == cmsSigCurveSetElemType) { + + _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*)cmsStageData(last); + for (i = 0; i < Data->nCurves; i++) { + if (IsDegenerated(Data->TheCurves[i])) + goto Error; + } + } + } + + for (t = 0; t < OriginalLut ->InputChannels; t++) { + Trans[t] = cmsBuildTabulatedToneCurve16(OriginalLut ->ContextID, PRELINEARIZATION_POINTS, NULL); + if (Trans[t] == NULL) goto Error; + } + + // Populate the curves + for (i=0; i < PRELINEARIZATION_POINTS; i++) { + + v = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); + + // Feed input with a gray ramp + for (t=0; t < OriginalLut ->InputChannels; t++) + In[t] = v; + + // Evaluate the gray value + cmsPipelineEvalFloat(In, Out, OriginalLut); + + // Store result in curve + for (t=0; t < OriginalLut ->InputChannels; t++) + Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); + } + + // Slope-limit the obtained curves + for (t = 0; t < OriginalLut ->InputChannels; t++) + SlopeLimiting(Trans[t]); + + // Check for validity + lIsSuitable = TRUE; + lIsLinear = TRUE; + for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) { + + // Exclude if already linear + if (!cmsIsToneCurveLinear(Trans[t])) + lIsLinear = FALSE; + + // Exclude if non-monotonic + if (!cmsIsToneCurveMonotonic(Trans[t])) + lIsSuitable = FALSE; + + if (IsDegenerated(Trans[t])) + lIsSuitable = FALSE; + } + + // If it is not suitable, just quit + if (!lIsSuitable) goto Error; + + // Invert curves if possible + for (t = 0; t < OriginalLut ->InputChannels; t++) { + TransReverse[t] = cmsReverseToneCurveEx(PRELINEARIZATION_POINTS, Trans[t]); + if (TransReverse[t] == NULL) goto Error; + } + + // Now inset the reversed curves at the begin of transform + LutPlusCurves = cmsPipelineDup(OriginalLut); + if (LutPlusCurves == NULL) goto Error; + + if (!cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse))) + goto Error; + + // Create the result LUT + OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels); + if (OptimizedLUT == NULL) goto Error; + + OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans); + + // Create and insert the curves at the beginning + if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe)) + goto Error; + + // Allocate the CLUT for result + OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL); + + // Add the CLUT to the destination LUT + if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe)) + goto Error; + + // Resample the LUT + if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error; + + // Free resources + for (t = 0; t < OriginalLut ->InputChannels; t++) { + + if (Trans[t]) cmsFreeToneCurve(Trans[t]); + if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); + } + + cmsPipelineFree(LutPlusCurves); + + + OptimizedPrelinCurves = _cmsStageGetPtrToCurveSet(OptimizedPrelinMpe); + OptimizedPrelinCLUT = (_cmsStageCLutData*) OptimizedCLUTmpe ->Data; + + // Set the evaluator if 8-bit + if (_cmsFormatterIs8bit(*InputFormat)) { + + Prelin8Data* p8 = PrelinOpt8alloc(OptimizedLUT ->ContextID, + OptimizedPrelinCLUT ->Params, + OptimizedPrelinCurves); + if (p8 == NULL) return FALSE; + + _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval8, (void*) p8, Prelin8free, Prelin8dup); + + } + else + { + Prelin16Data* p16 = PrelinOpt16alloc(OptimizedLUT ->ContextID, + OptimizedPrelinCLUT ->Params, + 3, OptimizedPrelinCurves, 3, NULL); + if (p16 == NULL) return FALSE; + + _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); + + } + + // Don't fix white on absolute colorimetric + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) + *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; + + if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) { + + if (!FixWhiteMisalignment(OptimizedLUT, ColorSpace, OutputColorSpace)) { + + return FALSE; + } + } + + // And return the obtained LUT + + cmsPipelineFree(OriginalLut); + *Lut = OptimizedLUT; + return TRUE; + +Error: + + for (t = 0; t < OriginalLut ->InputChannels; t++) { + + if (Trans[t]) cmsFreeToneCurve(Trans[t]); + if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); + } + + if (LutPlusCurves != NULL) cmsPipelineFree(LutPlusCurves); + if (OptimizedLUT != NULL) cmsPipelineFree(OptimizedLUT); + + return FALSE; + + cmsUNUSED_PARAMETER(Intent); + cmsUNUSED_PARAMETER(lIsLinear); +} + + +// Curves optimizer ------------------------------------------------------------------------------------------------------------------ + +static +void CurvesFree(cmsContext ContextID, void* ptr) +{ + Curves16Data* Data = (Curves16Data*) ptr; + cmsUInt32Number i; + + for (i=0; i < Data -> nCurves; i++) { + + _cmsFree(ContextID, Data ->Curves[i]); + } + + _cmsFree(ContextID, Data ->Curves); + _cmsFree(ContextID, ptr); +} + +static +void* CurvesDup(cmsContext ContextID, const void* ptr) +{ + Curves16Data* Data = (Curves16Data*)_cmsDupMem(ContextID, ptr, sizeof(Curves16Data)); + cmsUInt32Number i; + + if (Data == NULL) return NULL; + + Data->Curves = (cmsUInt16Number**) _cmsDupMem(ContextID, Data->Curves, Data->nCurves * sizeof(cmsUInt16Number*)); + + for (i=0; i < Data -> nCurves; i++) { + Data->Curves[i] = (cmsUInt16Number*) _cmsDupMem(ContextID, Data->Curves[i], Data->nElements * sizeof(cmsUInt16Number)); + } + + return (void*) Data; +} + +// Precomputes tables for 8-bit on input devicelink. +static +Curves16Data* CurvesAlloc(cmsContext ContextID, cmsUInt32Number nCurves, cmsUInt32Number nElements, cmsToneCurve** G) +{ + cmsUInt32Number i, j; + Curves16Data* c16; + + c16 = (Curves16Data*)_cmsMallocZero(ContextID, sizeof(Curves16Data)); + if (c16 == NULL) return NULL; + + c16 ->nCurves = nCurves; + c16 ->nElements = nElements; + + c16->Curves = (cmsUInt16Number**) _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*)); + if (c16->Curves == NULL) { + _cmsFree(ContextID, c16); + return NULL; + } + + for (i=0; i < nCurves; i++) { + + c16->Curves[i] = (cmsUInt16Number*) _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); + + if (c16->Curves[i] == NULL) { + + for (j=0; j < i; j++) { + _cmsFree(ContextID, c16->Curves[j]); + } + _cmsFree(ContextID, c16->Curves); + _cmsFree(ContextID, c16); + return NULL; + } + + if (nElements == 256U) { + + for (j=0; j < nElements; j++) { + + c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], FROM_8_TO_16(j)); + } + } + else { + + for (j=0; j < nElements; j++) { + c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], (cmsUInt16Number) j); + } + } + } + + return c16; +} + +static +void FastEvaluateCurves8(CMSREGISTER const cmsUInt16Number In[], + CMSREGISTER cmsUInt16Number Out[], + CMSREGISTER const void* D) +{ + Curves16Data* Data = (Curves16Data*) D; + int x; + cmsUInt32Number i; + + for (i=0; i < Data ->nCurves; i++) { + + x = (In[i] >> 8); + Out[i] = Data -> Curves[i][x]; + } +} + + +static +void FastEvaluateCurves16(CMSREGISTER const cmsUInt16Number In[], + CMSREGISTER cmsUInt16Number Out[], + CMSREGISTER const void* D) +{ + Curves16Data* Data = (Curves16Data*) D; + cmsUInt32Number i; + + for (i=0; i < Data ->nCurves; i++) { + Out[i] = Data -> Curves[i][In[i]]; + } +} + + +static +void FastIdentity16(CMSREGISTER const cmsUInt16Number In[], + CMSREGISTER cmsUInt16Number Out[], + CMSREGISTER const void* D) +{ + cmsPipeline* Lut = (cmsPipeline*) D; + cmsUInt32Number i; + + for (i=0; i < Lut ->InputChannels; i++) { + Out[i] = In[i]; + } +} + + +// If the target LUT holds only curves, the optimization procedure is to join all those +// curves together. That only works on curves and does not work on matrices. +static +cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + cmsToneCurve** GammaTables = NULL; + cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; + cmsUInt32Number i, j; + cmsPipeline* Src = *Lut; + cmsPipeline* Dest = NULL; + cmsStage* mpe; + cmsStage* ObtainedCurves = NULL; + + + // This is a lossy optimization! does not apply in floating-point cases + if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; + + // Only curves in this LUT? + for (mpe = cmsPipelineGetPtrToFirstStage(Src); + mpe != NULL; + mpe = cmsStageNext(mpe)) { + if (cmsStageType(mpe) != cmsSigCurveSetElemType) return FALSE; + } + + // Allocate an empty LUT + Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); + if (Dest == NULL) return FALSE; + + // Create target curves + GammaTables = (cmsToneCurve**) _cmsCalloc(Src ->ContextID, Src ->InputChannels, sizeof(cmsToneCurve*)); + if (GammaTables == NULL) goto Error; + + for (i=0; i < Src ->InputChannels; i++) { + GammaTables[i] = cmsBuildTabulatedToneCurve16(Src ->ContextID, PRELINEARIZATION_POINTS, NULL); + if (GammaTables[i] == NULL) goto Error; + } + + // Compute 16 bit result by using floating point + for (i=0; i < PRELINEARIZATION_POINTS; i++) { + + for (j=0; j < Src ->InputChannels; j++) + InFloat[j] = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); + + cmsPipelineEvalFloat(InFloat, OutFloat, Src); + + for (j=0; j < Src ->InputChannels; j++) + GammaTables[j] -> Table16[i] = _cmsQuickSaturateWord(OutFloat[j] * 65535.0); + } + + ObtainedCurves = cmsStageAllocToneCurves(Src ->ContextID, Src ->InputChannels, GammaTables); + if (ObtainedCurves == NULL) goto Error; + + for (i=0; i < Src ->InputChannels; i++) { + cmsFreeToneCurve(GammaTables[i]); + GammaTables[i] = NULL; + } + + if (GammaTables != NULL) { + _cmsFree(Src->ContextID, GammaTables); + GammaTables = NULL; + } + + // Maybe the curves are linear at the end + if (!AllCurvesAreLinear(ObtainedCurves)) { + _cmsStageToneCurvesData* Data; + + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves)) + goto Error; + Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves); + ObtainedCurves = NULL; + + // If the curves are to be applied in 8 bits, we can save memory + if (_cmsFormatterIs8bit(*InputFormat)) { + Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves); + + if (c16 == NULL) goto Error; + *dwFlags |= cmsFLAGS_NOCACHE; + _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup); + + } + else { + Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves); + + if (c16 == NULL) goto Error; + *dwFlags |= cmsFLAGS_NOCACHE; + _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup); + } + } + else { + + // LUT optimizes to nothing. Set the identity LUT + cmsStageFree(ObtainedCurves); + ObtainedCurves = NULL; + + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels))) + goto Error; + + *dwFlags |= cmsFLAGS_NOCACHE; + _cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL); + } + + // We are done. + cmsPipelineFree(Src); + *Lut = Dest; + return TRUE; + +Error: + + if (ObtainedCurves != NULL) cmsStageFree(ObtainedCurves); + if (GammaTables != NULL) { + for (i=0; i < Src ->InputChannels; i++) { + if (GammaTables[i] != NULL) cmsFreeToneCurve(GammaTables[i]); + } + + _cmsFree(Src ->ContextID, GammaTables); + } + + if (Dest != NULL) cmsPipelineFree(Dest); + return FALSE; + + cmsUNUSED_PARAMETER(Intent); + cmsUNUSED_PARAMETER(InputFormat); + cmsUNUSED_PARAMETER(OutputFormat); + cmsUNUSED_PARAMETER(dwFlags); +} + +// ------------------------------------------------------------------------------------------------------------------------------------- +// LUT is Shaper - Matrix - Matrix - Shaper, which is very frequent when combining two matrix-shaper profiles + + +static +void FreeMatShaper(cmsContext ContextID, void* Data) +{ + if (Data != NULL) _cmsFree(ContextID, Data); +} + +static +void* DupMatShaper(cmsContext ContextID, const void* Data) +{ + return _cmsDupMem(ContextID, Data, sizeof(MatShaper8Data)); +} + + +// A fast matrix-shaper evaluator for 8 bits. This is a bit ticky since I'm using 1.14 signed fixed point +// to accomplish some performance. Actually it takes 256x3 16 bits tables and 16385 x 3 tables of 8 bits, +// in total about 50K, and the performance boost is huge! +static +void MatShaperEval16(CMSREGISTER const cmsUInt16Number In[], + CMSREGISTER cmsUInt16Number Out[], + CMSREGISTER const void* D) +{ + MatShaper8Data* p = (MatShaper8Data*) D; + cmsS1Fixed14Number l1, l2, l3, r, g, b; + cmsUInt32Number ri, gi, bi; + + // In this case (and only in this case!) we can use this simplification since + // In[] is assured to come from a 8 bit number. (a << 8 | a) + ri = In[0] & 0xFFU; + gi = In[1] & 0xFFU; + bi = In[2] & 0xFFU; + + // Across first shaper, which also converts to 1.14 fixed point + r = p->Shaper1R[ri]; + g = p->Shaper1G[gi]; + b = p->Shaper1B[bi]; + + // Evaluate the matrix in 1.14 fixed point + l1 = (p->Mat[0][0] * r + p->Mat[0][1] * g + p->Mat[0][2] * b + p->Off[0] + 0x2000) >> 14; + l2 = (p->Mat[1][0] * r + p->Mat[1][1] * g + p->Mat[1][2] * b + p->Off[1] + 0x2000) >> 14; + l3 = (p->Mat[2][0] * r + p->Mat[2][1] * g + p->Mat[2][2] * b + p->Off[2] + 0x2000) >> 14; + + // Now we have to clip to 0..1.0 range + ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384U : (cmsUInt32Number) l1); + gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384U : (cmsUInt32Number) l2); + bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384U : (cmsUInt32Number) l3); + + // And across second shaper, + Out[0] = p->Shaper2R[ri]; + Out[1] = p->Shaper2G[gi]; + Out[2] = p->Shaper2B[bi]; + +} + +// This table converts from 8 bits to 1.14 after applying the curve +static +void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) +{ + int i; + cmsFloat32Number R, y; + + for (i=0; i < 256; i++) { + + R = (cmsFloat32Number) (i / 255.0); + y = cmsEvalToneCurveFloat(Curve, R); + + if (y < 131072.0) + Table[i] = DOUBLE_TO_1FIXED14(y); + else + Table[i] = 0x7fffffff; + } +} + +// This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after applying the curve +static +void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput) +{ + int i; + cmsFloat32Number R, Val; + + for (i=0; i < 16385; i++) { + + R = (cmsFloat32Number) (i / 16384.0); + Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 + + if (Val < 0) + Val = 0; + + if (Val > 1.0) + Val = 1.0; + + if (Is8BitsOutput) { + + // If 8 bits output, we can optimize further by computing the / 257 part. + // first we compute the resulting byte and then we store the byte times + // 257. This quantization allows to round very quick by doing a >> 8, but + // since the low byte is always equal to msb, we can do a & 0xff and this works! + cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0); + cmsUInt8Number b = FROM_16_TO_8(w); + + Table[i] = FROM_8_TO_16(b); + } + else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); + } +} + +// Compute the matrix-shaper structure +static +cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, cmsVEC3* Off, cmsToneCurve* Curve2[3], cmsUInt32Number* OutputFormat) +{ + MatShaper8Data* p; + int i, j; + cmsBool Is8Bits = _cmsFormatterIs8bit(*OutputFormat); + + // Allocate a big chuck of memory to store precomputed tables + p = (MatShaper8Data*) _cmsMalloc(Dest ->ContextID, sizeof(MatShaper8Data)); + if (p == NULL) return FALSE; + + p -> ContextID = Dest -> ContextID; + + // Precompute tables + FillFirstShaper(p ->Shaper1R, Curve1[0]); + FillFirstShaper(p ->Shaper1G, Curve1[1]); + FillFirstShaper(p ->Shaper1B, Curve1[2]); + + FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits); + FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits); + FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits); + + // Convert matrix to nFixed14. Note that those values may take more than 16 bits + for (i=0; i < 3; i++) { + for (j=0; j < 3; j++) { + p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]); + } + } + + for (i=0; i < 3; i++) { + + if (Off == NULL) { + p ->Off[i] = 0; + } + else { + p ->Off[i] = DOUBLE_TO_1FIXED14(Off->n[i]); + } + } + + // Mark as optimized for faster formatter + if (Is8Bits) + *OutputFormat |= OPTIMIZED_SH(1); + + // Fill function pointers + _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper); + return TRUE; +} + +// 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast! +static +cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + cmsStage* Curve1, *Curve2; + cmsStage* Matrix1, *Matrix2; + cmsMAT3 res; + cmsBool IdentityMat; + cmsPipeline* Dest, *Src; + cmsFloat64Number* Offset; + + // Only works on RGB to RGB + if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE; + + // Only works on 8 bit input + if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE; + + // Seems suitable, proceed + Src = *Lut; + + // Check for: + // + // shaper-matrix-matrix-shaper + // shaper-matrix-shaper + // + // Both of those constructs are possible (first because abs. colorimetric). + // additionally, In the first case, the input matrix offset should be zero. + + IdentityMat = FALSE; + if (cmsPipelineCheckAndRetreiveStages(Src, 4, + cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + &Curve1, &Matrix1, &Matrix2, &Curve2)) { + + // Get both matrices + _cmsStageMatrixData* Data1 = (_cmsStageMatrixData*)cmsStageData(Matrix1); + _cmsStageMatrixData* Data2 = (_cmsStageMatrixData*)cmsStageData(Matrix2); + + // Input offset should be zero + if (Data1->Offset != NULL) return FALSE; + + // Multiply both matrices to get the result + _cmsMAT3per(&res, (cmsMAT3*)Data2->Double, (cmsMAT3*)Data1->Double); + + // Only 2nd matrix has offset, or it is zero + Offset = Data2->Offset; + + // Now the result is in res + Data2 -> Offset. Maybe is a plain identity? + if (_cmsMAT3isIdentity(&res) && Offset == NULL) { + + // We can get rid of full matrix + IdentityMat = TRUE; + } + + } + else { + + if (cmsPipelineCheckAndRetreiveStages(Src, 3, + cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + &Curve1, &Matrix1, &Curve2)) { + + _cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1); + + // Copy the matrix to our result + memcpy(&res, Data->Double, sizeof(res)); + + // Preserve the Odffset (may be NULL as a zero offset) + Offset = Data->Offset; + + if (_cmsMAT3isIdentity(&res) && Offset == NULL) { + + // We can get rid of full matrix + IdentityMat = TRUE; + } + } + else + return FALSE; // Not optimizeable this time + + } + + // Allocate an empty LUT + Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); + if (!Dest) return FALSE; + + // Assamble the new LUT + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1))) + goto Error; + + if (!IdentityMat) { + + if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest->ContextID, 3, 3, (const cmsFloat64Number*)&res, Offset))) + goto Error; + } + + if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2))) + goto Error; + + // If identity on matrix, we can further optimize the curves, so call the join curves routine + if (IdentityMat) { + + OptimizeByJoiningCurves(&Dest, Intent, InputFormat, OutputFormat, dwFlags); + } + else { + _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1); + _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); + + // In this particular optimization, cache does not help as it takes more time to deal with + // the cache that with the pixel handling + *dwFlags |= cmsFLAGS_NOCACHE; + + // Setup the optimizarion routines + SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Offset, mpeC2->TheCurves, OutputFormat); + } + + cmsPipelineFree(Src); + *Lut = Dest; + return TRUE; +Error: + // Leave Src unchanged + cmsPipelineFree(Dest); + return FALSE; +} + + +// ------------------------------------------------------------------------------------------------------------------------------------- +// Optimization plug-ins + +// List of optimizations +typedef struct _cmsOptimizationCollection_st { + + _cmsOPToptimizeFn OptimizePtr; + + struct _cmsOptimizationCollection_st *Next; + +} _cmsOptimizationCollection; + + +// The built-in list. We currently implement 4 types of optimizations. Joining of curves, matrix-shaper, linearization and resampling +static _cmsOptimizationCollection DefaultOptimization[] = { + + { OptimizeByJoiningCurves, &DefaultOptimization[1] }, + { OptimizeMatrixShaper, &DefaultOptimization[2] }, + { OptimizeByComputingLinearization, &DefaultOptimization[3] }, + { OptimizeByResampling, NULL } +}; + +// The linked list head +_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginOptimizationList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsOptimizationPluginChunkType newHead = { NULL }; + _cmsOptimizationCollection* entry; + _cmsOptimizationCollection* Anterior = NULL; + _cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin]; + + _cmsAssert(ctx != NULL); + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->OptimizationCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.OptimizationCollection == NULL) + newHead.OptimizationCollection = newEntry; + } + + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType)); +} + +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginOptimizationList(ctx, src); + } + else { + static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL }; + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType)); + } +} + + +// Register new ways to optimize +cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); + _cmsOptimizationCollection* fl; + + if (Data == NULL) { + + ctx->OptimizationCollection = NULL; + return TRUE; + } + + // Optimizer callback is required + if (Plugin ->OptimizePtr == NULL) return FALSE; + + fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection)); + if (fl == NULL) return FALSE; + + // Copy the parameters + fl ->OptimizePtr = Plugin ->OptimizePtr; + + // Keep linked list + fl ->Next = ctx->OptimizationCollection; + + // Set the head + ctx ->OptimizationCollection = fl; + + // All is ok + return TRUE; +} + +// The entry point for LUT optimization +cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** PtrLut, + cmsUInt32Number Intent, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags) +{ + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); + _cmsOptimizationCollection* Opts; + cmsBool AnySuccess = FALSE; + + // A CLUT is being asked, so force this specific optimization + if (*dwFlags & cmsFLAGS_FORCE_CLUT) { + + PreOptimize(*PtrLut); + return OptimizeByResampling(PtrLut, Intent, InputFormat, OutputFormat, dwFlags); + } + + // Anything to optimize? + if ((*PtrLut) ->Elements == NULL) { + _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); + return TRUE; + } + + // Try to get rid of identities and trivial conversions. + AnySuccess = PreOptimize(*PtrLut); + + // After removal do we end with an identity? + if ((*PtrLut) ->Elements == NULL) { + _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); + return TRUE; + } + + // Do not optimize, keep all precision + if (*dwFlags & cmsFLAGS_NOOPTIMIZE) + return FALSE; + + // Try plug-in optimizations + for (Opts = ctx->OptimizationCollection; + Opts != NULL; + Opts = Opts ->Next) { + + // If one schema succeeded, we are done + if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { + + return TRUE; // Optimized! + } + } + + // Try built-in optimizations + for (Opts = DefaultOptimization; + Opts != NULL; + Opts = Opts ->Next) { + + if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { + + return TRUE; + } + } + + // Only simple optimizations succeeded + return AnySuccess; +} + + + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmspack.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmspack.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmspack.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmspack.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,3462 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// This module handles all formats supported by lcms. There are two flavors, 16 bits and +// floating point. Floating point is supported only in a subset, those formats holding +// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component +// as special case) + +// --------------------------------------------------------------------------- + + +// This macro return words stored as big endian +#define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8)) + +// These macros handles reversing (negative) +#define REVERSE_FLAVOR_8(x) ((cmsUInt8Number) (0xff-(x))) +#define REVERSE_FLAVOR_16(x) ((cmsUInt16Number)(0xffff-(x))) + +// * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256 +cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x) +{ + int a = (x << 8 | x) >> 8; // * 257 / 256 + if ( a > 0xffff) return 0xffff; + return (cmsUInt16Number) a; +} + +// * 0xf00 / 0xffff = * 256 / 257 +cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x) +{ + return (cmsUInt16Number) (((x << 8) + 0x80) / 257); +} + + +typedef struct { + cmsUInt32Number Type; + cmsUInt32Number Mask; + cmsFormatter16 Frm; + +} cmsFormatters16; + +typedef struct { + cmsUInt32Number Type; + cmsUInt32Number Mask; + cmsFormatterFloat Frm; + +} cmsFormattersFloat; + + +#define ANYSPACE COLORSPACE_SH(31) +#define ANYCHANNELS CHANNELS_SH(15) +#define ANYEXTRA EXTRA_SH(7) +#define ANYPLANAR PLANAR_SH(1) +#define ANYENDIAN ENDIAN16_SH(1) +#define ANYSWAP DOSWAP_SH(1) +#define ANYSWAPFIRST SWAPFIRST_SH(1) +#define ANYFLAVOR FLAVOR_SH(1) + + +// Suppress waning about info never being used + +#ifdef _MSC_VER +#pragma warning(disable : 4100) +#endif + +// Unpacking routines (16 bits) ---------------------------------------------------------------------------------------- + + +// Does almost everything but is slow +static +cmsUInt8Number* UnrollChunkyBytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt16Number v; + cmsUInt32Number i; + + if (ExtraFirst) { + accum += Extra; + } + + for (i=0; i < nChan; i++) { + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = FROM_8_TO_16(*accum); + v = Reverse ? REVERSE_FLAVOR_16(v) : v; + wIn[index] = v; + accum++; + } + + if (!ExtraFirst) { + accum += Extra; + } + + if (Extra == 0 && SwapFirst) { + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; + } + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); + +} + +// Extra channels are just ignored because come in the next planes +static +cmsUInt8Number* UnrollPlanarBytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number i; + cmsUInt8Number* Init = accum; + + if (DoSwap ^ SwapFirst) { + accum += T_EXTRA(info -> InputFormat) * Stride; + } + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + cmsUInt16Number v = FROM_8_TO_16(*accum); + + wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; + accum += Stride; + } + + return (Init + 1); +} + +// Special cases, provided for performance +static +cmsUInt8Number* Unroll4Bytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = FROM_8_TO_16(*accum); accum++; // C + wIn[1] = FROM_8_TO_16(*accum); accum++; // M + wIn[2] = FROM_8_TO_16(*accum); accum++; // Y + wIn[3] = FROM_8_TO_16(*accum); accum++; // K + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll4BytesReverse(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // C + wIn[1] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // M + wIn[2] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // Y + wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll4BytesSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[3] = FROM_8_TO_16(*accum); accum++; // K + wIn[0] = FROM_8_TO_16(*accum); accum++; // C + wIn[1] = FROM_8_TO_16(*accum); accum++; // M + wIn[2] = FROM_8_TO_16(*accum); accum++; // Y + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// KYMC +static +cmsUInt8Number* Unroll4BytesSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[3] = FROM_8_TO_16(*accum); accum++; // K + wIn[2] = FROM_8_TO_16(*accum); accum++; // Y + wIn[1] = FROM_8_TO_16(*accum); accum++; // M + wIn[0] = FROM_8_TO_16(*accum); accum++; // C + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll4BytesSwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[2] = FROM_8_TO_16(*accum); accum++; // K + wIn[1] = FROM_8_TO_16(*accum); accum++; // Y + wIn[0] = FROM_8_TO_16(*accum); accum++; // M + wIn[3] = FROM_8_TO_16(*accum); accum++; // C + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3Bytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3BytesSkip1Swap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + accum++; // A + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3BytesSkip1SwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + accum++; // A + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3BytesSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + accum++; // A + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +// BRG +static +cmsUInt8Number* Unroll3BytesSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* UnrollLabV2_8(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L + wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a + wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* UnrollALabV2_8(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + accum++; // A + wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L + wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a + wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* UnrollLabV2_16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // L + wIn[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // a + wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// for duplex +static +cmsUInt8Number* Unroll2Bytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = FROM_8_TO_16(*accum); accum++; // ch1 + wIn[1] = FROM_8_TO_16(*accum); accum++; // ch2 + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + + + +// Monochrome duplicates L into RGB for null-transforms +static +cmsUInt8Number* Unroll1Byte(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Unroll1ByteSkip1(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L + accum += 1; + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll1ByteSkip2(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L + accum += 2; + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll1ByteReversed(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++; // L + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* UnrollAnyWords(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number i; + + if (ExtraFirst) { + accum += Extra * sizeof(cmsUInt16Number); + } + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + cmsUInt16Number v = *(cmsUInt16Number*) accum; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; + + accum += sizeof(cmsUInt16Number); + } + + if (!ExtraFirst) { + accum += Extra * sizeof(cmsUInt16Number); + } + + if (Extra == 0 && SwapFirst) { + + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; + } + + return accum; + + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* UnrollPlanarWords(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap= T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse= T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat); + cmsUInt32Number i; + cmsUInt8Number* Init = accum; + + if (DoSwap) { + accum += T_EXTRA(info -> InputFormat) * Stride; + } + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + cmsUInt16Number v = *(cmsUInt16Number*) accum; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; + + accum += Stride; + } + + return (Init + sizeof(cmsUInt16Number)); +} + + +static +cmsUInt8Number* Unroll4Words(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y + wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll4WordsReverse(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // C + wIn[1] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // M + wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // Y + wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll4WordsSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// KYMC +static +cmsUInt8Number* Unroll4WordsSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll4WordsSwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // K + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // Y + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // M + wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3Words(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C R + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y B + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3WordsSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // C R + wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M G + wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // Y B + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3WordsSkip1Swap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + accum += 2; // A + wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // R + wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G + wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll3WordsSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + accum += 2; // A + wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // R + wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G + wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll1Word(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll1WordReversed(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll1WordSkip3(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; + + accum += 8; + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Unroll2Words(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // ch1 + wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // ch2 + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +// This is a conversion of Lab double to 16 bits +static +cmsUInt8Number* UnrollLabDoubleTo16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + if (T_PLANAR(info -> InputFormat)) { + + cmsCIELab Lab; + cmsUInt8Number* pos_L; + cmsUInt8Number* pos_a; + cmsUInt8Number* pos_b; + + pos_L = accum; + pos_a = accum + Stride; + pos_b = accum + Stride * 2; + + Lab.L = *(cmsFloat64Number*) pos_L; + Lab.a = *(cmsFloat64Number*) pos_a; + Lab.b = *(cmsFloat64Number*) pos_b; + + cmsFloat2LabEncoded(wIn, &Lab); + return accum + sizeof(cmsFloat64Number); + } + else { + + cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum); + accum += sizeof(cmsCIELab) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number); + return accum; + } +} + + +// This is a conversion of Lab float to 16 bits +static +cmsUInt8Number* UnrollLabFloatTo16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsCIELab Lab; + + if (T_PLANAR(info -> InputFormat)) { + + cmsUInt8Number* pos_L; + cmsUInt8Number* pos_a; + cmsUInt8Number* pos_b; + + pos_L = accum; + pos_a = accum + Stride; + pos_b = accum + Stride * 2; + + Lab.L = *(cmsFloat32Number*)pos_L; + Lab.a = *(cmsFloat32Number*)pos_a; + Lab.b = *(cmsFloat32Number*)pos_b; + + cmsFloat2LabEncoded(wIn, &Lab); + return accum + sizeof(cmsFloat32Number); + } + else { + + Lab.L = ((cmsFloat32Number*) accum)[0]; + Lab.a = ((cmsFloat32Number*) accum)[1]; + Lab.b = ((cmsFloat32Number*) accum)[2]; + + cmsFloat2LabEncoded(wIn, &Lab); + accum += (3 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); + return accum; + } +} + +// This is a conversion of XYZ double to 16 bits +static +cmsUInt8Number* UnrollXYZDoubleTo16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + if (T_PLANAR(info -> InputFormat)) { + + cmsCIEXYZ XYZ; + cmsUInt8Number* pos_X; + cmsUInt8Number* pos_Y; + cmsUInt8Number* pos_Z; + + pos_X = accum; + pos_Y = accum + Stride; + pos_Z = accum + Stride * 2; + + XYZ.X = *(cmsFloat64Number*)pos_X; + XYZ.Y = *(cmsFloat64Number*)pos_Y; + XYZ.Z = *(cmsFloat64Number*)pos_Z; + + cmsFloat2XYZEncoded(wIn, &XYZ); + + return accum + sizeof(cmsFloat64Number); + + } + + else { + cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum); + accum += sizeof(cmsCIEXYZ) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number); + + return accum; + } +} + +// This is a conversion of XYZ float to 16 bits +static +cmsUInt8Number* UnrollXYZFloatTo16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + if (T_PLANAR(info -> InputFormat)) { + + cmsCIEXYZ XYZ; + cmsUInt8Number* pos_X; + cmsUInt8Number* pos_Y; + cmsUInt8Number* pos_Z; + + pos_X = accum; + pos_Y = accum + Stride; + pos_Z = accum + Stride * 2; + + XYZ.X = *(cmsFloat32Number*)pos_X; + XYZ.Y = *(cmsFloat32Number*)pos_Y; + XYZ.Z = *(cmsFloat32Number*)pos_Z; + + cmsFloat2XYZEncoded(wIn, &XYZ); + + return accum + sizeof(cmsFloat32Number); + + } + + else { + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + cmsCIEXYZ XYZ; + + XYZ.X = Pt[0]; + XYZ.Y = Pt[1]; + XYZ.Z = Pt[2]; + cmsFloat2XYZEncoded(wIn, &XYZ); + + accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number); + + return accum; + } +} + +// Check if space is marked as ink +cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type) +{ + switch (T_COLORSPACE(Type)) { + + case PT_CMY: + case PT_CMYK: + case PT_MCH5: + case PT_MCH6: + case PT_MCH7: + case PT_MCH8: + case PT_MCH9: + case PT_MCH10: + case PT_MCH11: + case PT_MCH12: + case PT_MCH13: + case PT_MCH14: + case PT_MCH15: return TRUE; + + default: return FALSE; + } +} + +// Return the size in bytes of a given formatter +static +cmsUInt32Number PixelSize(cmsUInt32Number Format) +{ + cmsUInt32Number fmt_bytes = T_BYTES(Format); + + // For double, the T_BYTES field is zero + if (fmt_bytes == 0) + return sizeof(cmsUInt64Number); + + // Otherwise, it is already correct for all formats + return fmt_bytes; +} + +// Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits +static +cmsUInt8Number* UnrollDoubleTo16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Planar = T_PLANAR(info -> InputFormat); + cmsFloat64Number v; + cmsUInt16Number vi; + cmsUInt32Number i, start = 0; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + + + Stride /= PixelSize(info->InputFormat); + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[(i + start) * Stride]; + else + v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[i + start]; + + vi = _cmsQuickSaturateWord(v * maximum); + + if (Reverse) + vi = REVERSE_FLAVOR_16(vi); + + wIn[index] = vi; + } + + + if (Extra == 0 && SwapFirst) { + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsFloat64Number); + else + return accum + (nChan + Extra) * sizeof(cmsFloat64Number); +} + + + +static +cmsUInt8Number* UnrollFloatTo16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + cmsUInt16Number vi; + cmsUInt32Number i, start = 0; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + + Stride /= PixelSize(info->InputFormat); + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; + else + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start]; + + vi = _cmsQuickSaturateWord(v * maximum); + + if (Reverse) + vi = REVERSE_FLAVOR_16(vi); + + wIn[index] = vi; + } + + + if (Extra == 0 && SwapFirst) { + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsFloat32Number); + else + return accum + (nChan + Extra) * sizeof(cmsFloat32Number); +} + + + + +// For 1 channel, we need to duplicate data (it comes in 0..1.0 range) +static +cmsUInt8Number* UnrollDouble1Chan(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsFloat64Number* Inks = (cmsFloat64Number*) accum; + + wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0); + + return accum + sizeof(cmsFloat64Number); + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +//------------------------------------------------------------------------------------------------------------------- + +// For anything going from cmsFloat32Number +static +cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + cmsUInt32Number i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; + + Stride /= PixelSize(info->InputFormat); + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; + else + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start]; + + v /= maximum; + + wIn[index] = Reverse ? 1 - v : v; + } + + + if (Extra == 0 && SwapFirst) { + cmsFloat32Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); + wIn[nChan-1] = tmp; + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsFloat32Number); + else + return accum + (nChan + Extra) * sizeof(cmsFloat32Number); +} + +// For anything going from double + +static +cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Planar = T_PLANAR(info -> InputFormat); + cmsFloat64Number v; + cmsUInt32Number i, start = 0; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; + + Stride /= PixelSize(info->InputFormat); + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[(i + start) * Stride]; + else + v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start]; + + v /= maximum; + + wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v); + } + + + if (Extra == 0 && SwapFirst) { + cmsFloat32Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); + wIn[nChan-1] = tmp; + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsFloat64Number); + else + return accum + (nChan + Extra) * sizeof(cmsFloat64Number); +} + + + +// From Lab double to cmsFloat32Number +static +cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Pt = (cmsFloat64Number*) accum; + + if (T_PLANAR(info -> InputFormat)) { + + Stride /= PixelSize(info->InputFormat); + + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1 + wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0); + + return accum + sizeof(cmsFloat64Number); + } + else { + + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1 + wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0); + + accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); + return accum; + } +} + +// From Lab double to cmsFloat32Number +static +cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + + if (T_PLANAR(info -> InputFormat)) { + + Stride /= PixelSize(info->InputFormat); + + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1 + wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0); + + return accum + sizeof(cmsFloat32Number); + } + else { + + wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0); // form -128..+127 to 0..1 + wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0); + + accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat)); + return accum; + } +} + + + +// 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF) +static +cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Pt = (cmsFloat64Number*) accum; + + if (T_PLANAR(info -> InputFormat)) { + + Stride /= PixelSize(info->InputFormat); + + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); + wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ); + + return accum + sizeof(cmsFloat64Number); + } + else { + + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); + wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); + + accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); + return accum; + } +} + +static +cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + + if (T_PLANAR(info -> InputFormat)) { + + Stride /= PixelSize(info->InputFormat); + + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ); + wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ); + + return accum + sizeof(cmsFloat32Number); + } + else { + + wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ); + wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); + wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); + + accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat)); + return accum; + } +} + + + +// Packing routines ----------------------------------------------------------------------------------------------------------- + + +// Generic chunky for byte + +static +cmsUInt8Number* PackAnyBytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt8Number* swap1; + cmsUInt8Number v = 0; + cmsUInt32Number i; + + swap1 = output; + + if (ExtraFirst) { + output += Extra; + } + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = FROM_16_TO_8(wOut[index]); + + if (Reverse) + v = REVERSE_FLAVOR_8(v); + + *output++ = v; + } + + if (!ExtraFirst) { + output += Extra; + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, nChan-1); + *swap1 = v; + } + + + return output; + + cmsUNUSED_PARAMETER(Stride); +} + + + +static +cmsUInt8Number* PackAnyWords(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); + cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt16Number* swap1; + cmsUInt16Number v = 0; + cmsUInt32Number i; + + swap1 = (cmsUInt16Number*) output; + + if (ExtraFirst) { + output += Extra * sizeof(cmsUInt16Number); + } + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index]; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + if (Reverse) + v = REVERSE_FLAVOR_16(v); + + *(cmsUInt16Number*) output = v; + + output += sizeof(cmsUInt16Number); + } + + if (!ExtraFirst) { + output += Extra * sizeof(cmsUInt16Number); + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); + *swap1 = v; + } + + + return output; + + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* PackPlanarBytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); + cmsUInt32Number i; + cmsUInt8Number* Init = output; + + + if (DoSwap ^ SwapFirst) { + output += T_EXTRA(info -> OutputFormat) * Stride; + } + + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + cmsUInt8Number v = FROM_16_TO_8(wOut[index]); + + *(cmsUInt8Number*) output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v); + output += Stride; + } + + return (Init + 1); + + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* PackPlanarWords(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); + cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat); + cmsUInt32Number i; + cmsUInt8Number* Init = output; + cmsUInt16Number v; + + if (DoSwap) { + output += T_EXTRA(info -> OutputFormat) * Stride; + } + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index]; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + if (Reverse) + v = REVERSE_FLAVOR_16(v); + + *(cmsUInt16Number*) output = v; + output += Stride; + } + + return (Init + sizeof(cmsUInt16Number)); +} + +// CMYKcm (unrolled for speed) + +static +cmsUInt8Number* Pack6Bytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[3]); + *output++ = FROM_16_TO_8(wOut[4]); + *output++ = FROM_16_TO_8(wOut[5]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// KCMYcm + +static +cmsUInt8Number* Pack6BytesSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[5]); + *output++ = FROM_16_TO_8(wOut[4]); + *output++ = FROM_16_TO_8(wOut[3]); + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// CMYKcm +static +cmsUInt8Number* Pack6Words(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[3]; + output+= 2; + *(cmsUInt16Number*) output = wOut[4]; + output+= 2; + *(cmsUInt16Number*) output = wOut[5]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// KCMYcm +static +cmsUInt8Number* Pack6WordsSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[5]; + output+= 2; + *(cmsUInt16Number*) output = wOut[4]; + output+= 2; + *(cmsUInt16Number*) output = wOut[3]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack4Bytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[3]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack4BytesReverse(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[0])); + *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[1])); + *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[2])); + *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3])); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack4BytesSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[3]); + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// ABGR +static +cmsUInt8Number* Pack4BytesSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[3]); + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack4BytesSwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[3]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack4Words(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[3]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack4WordsReverse(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]); + output+= 2; + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[1]); + output+= 2; + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[2]); + output+= 2; + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[3]); + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// ABGR +static +cmsUInt8Number* Pack4WordsSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[3]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +// CMYK +static +cmsUInt8Number* Pack4WordsBigEndian(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[3]); + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* PackLabV2_8(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0])); + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1])); + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* PackALabV2_8(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output++; + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0])); + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1])); + *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* PackLabV2_16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[0]); + output += 2; + *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[1]); + output += 2; + *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[2]); + output += 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3Bytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesOptimized(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = (wOut[0] & 0xFFU); + *output++ = (wOut[1] & 0xFFU); + *output++ = (wOut[2] & 0xFFU); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesSwapOptimized(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = (wOut[2] & 0xFFU); + *output++ = (wOut[1] & 0xFFU); + *output++ = (wOut[0] & 0xFFU); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack3Words(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3WordsSwap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3WordsBigEndian(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]); + output+= 2; + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]); + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesAndSkip1(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + output++; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesAndSkip1Optimized(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = (wOut[0] & 0xFFU); + *output++ = (wOut[1] & 0xFFU); + *output++ = (wOut[2] & 0xFFU); + output++; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output++; + *output++ = FROM_16_TO_8(wOut[0]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[2]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output++; + *output++ = (wOut[0] & 0xFFU); + *output++ = (wOut[1] & 0xFFU); + *output++ = (wOut[2] & 0xFFU); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesAndSkip1Swap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output++; + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output++; + *output++ = (wOut[2] & 0xFFU); + *output++ = (wOut[1] & 0xFFU); + *output++ = (wOut[0] & 0xFFU); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[2]); + *output++ = FROM_16_TO_8(wOut[1]); + *output++ = FROM_16_TO_8(wOut[0]); + output++; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = (wOut[2] & 0xFFU); + *output++ = (wOut[1] & 0xFFU); + *output++ = (wOut[0] & 0xFFU); + output++; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3WordsAndSkip1(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack3WordsAndSkip1Swap(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[2]; + output+= 2; + *(cmsUInt16Number*) output = wOut[1]; + output+= 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + + +static +cmsUInt8Number* Pack1Byte(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack1ByteReversed(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0])); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack1ByteSkip1(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *output++ = FROM_16_TO_8(wOut[0]); + output++; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack1ByteSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output++; + *output++ = FROM_16_TO_8(wOut[0]); + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack1Word(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack1WordReversed(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]); + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack1WordBigEndian(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]); + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +static +cmsUInt8Number* Pack1WordSkip1(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + *(cmsUInt16Number*) output = wOut[0]; + output+= 4; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* Pack1WordSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + output += 2; + *(cmsUInt16Number*) output = wOut[0]; + output+= 2; + + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + + +// Unencoded Float values -- don't try optimize speed +static +cmsUInt8Number* PackLabDoubleFrom16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + + if (T_PLANAR(info -> OutputFormat)) { + + cmsCIELab Lab; + cmsFloat64Number* Out = (cmsFloat64Number*) output; + cmsLabEncoded2Float(&Lab, wOut); + + Out[0] = Lab.L; + Out[Stride] = Lab.a; + Out[Stride*2] = Lab.b; + + return output + sizeof(cmsFloat64Number); + } + else { + + cmsLabEncoded2Float((cmsCIELab*) output, wOut); + return output + (sizeof(cmsCIELab) + T_EXTRA(info ->OutputFormat) * sizeof(cmsFloat64Number)); + } +} + + +static +cmsUInt8Number* PackLabFloatFrom16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsCIELab Lab; + cmsLabEncoded2Float(&Lab, wOut); + + if (T_PLANAR(info -> OutputFormat)) { + + cmsFloat32Number* Out = (cmsFloat32Number*) output; + + Stride /= PixelSize(info->OutputFormat); + + Out[0] = (cmsFloat32Number)Lab.L; + Out[Stride] = (cmsFloat32Number)Lab.a; + Out[Stride*2] = (cmsFloat32Number)Lab.b; + + return output + sizeof(cmsFloat32Number); + } + else { + + ((cmsFloat32Number*) output)[0] = (cmsFloat32Number) Lab.L; + ((cmsFloat32Number*) output)[1] = (cmsFloat32Number) Lab.a; + ((cmsFloat32Number*) output)[2] = (cmsFloat32Number) Lab.b; + + return output + (3 + T_EXTRA(info ->OutputFormat)) * sizeof(cmsFloat32Number); + } +} + +static +cmsUInt8Number* PackXYZDoubleFrom16(CMSREGISTER _cmsTRANSFORM* Info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + if (T_PLANAR(Info -> OutputFormat)) { + + cmsCIEXYZ XYZ; + cmsFloat64Number* Out = (cmsFloat64Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); + + Stride /= PixelSize(Info->OutputFormat); + + Out[0] = XYZ.X; + Out[Stride] = XYZ.Y; + Out[Stride*2] = XYZ.Z; + + return output + sizeof(cmsFloat64Number); + + } + else { + + cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut); + + return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + } +} + +static +cmsUInt8Number* PackXYZFloatFrom16(CMSREGISTER _cmsTRANSFORM* Info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + if (T_PLANAR(Info -> OutputFormat)) { + + cmsCIEXYZ XYZ; + cmsFloat32Number* Out = (cmsFloat32Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); + + Stride /= PixelSize(Info->OutputFormat); + + Out[0] = (cmsFloat32Number) XYZ.X; + Out[Stride] = (cmsFloat32Number) XYZ.Y; + Out[Stride*2] = (cmsFloat32Number) XYZ.Z; + + return output + sizeof(cmsFloat32Number); + + } + else { + + cmsCIEXYZ XYZ; + cmsFloat32Number* Out = (cmsFloat32Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); + + Out[0] = (cmsFloat32Number) XYZ.X; + Out[1] = (cmsFloat32Number) XYZ.Y; + Out[2] = (cmsFloat32Number) XYZ.Z; + + return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + } +} + +static +cmsUInt8Number* PackDoubleFrom16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info -> OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0; + cmsFloat64Number v = 0; + cmsFloat64Number* swap1 = (cmsFloat64Number*) output; + cmsUInt32Number i, start = 0; + + Stride /= PixelSize(info->OutputFormat); + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = (cmsFloat64Number) wOut[index] / maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsFloat64Number*) output)[(i + start) * Stride]= v; + else + ((cmsFloat64Number*) output)[i + start] = v; + } + + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); + *swap1 = v; + } + + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsFloat64Number); + else + return output + (nChan + Extra) * sizeof(cmsFloat64Number); + +} + + +static +cmsUInt8Number* PackFloatFrom16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 655.35 : 65535.0; + cmsFloat64Number v = 0; + cmsFloat32Number* swap1 = (cmsFloat32Number*)output; + cmsUInt32Number i, start = 0; + + Stride /= PixelSize(info->OutputFormat); + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = (cmsFloat64Number)wOut[index] / maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsFloat32Number*)output)[(i + start) * Stride] = (cmsFloat32Number)v; + else + ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v; + } + + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number)); + *swap1 = (cmsFloat32Number)v; + } + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsFloat32Number); + else + return output + (nChan + Extra) * sizeof(cmsFloat32Number); +} + + + +// -------------------------------------------------------------------------------------------------------- + +static +cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0; + cmsFloat32Number* swap1 = (cmsFloat32Number*)output; + cmsFloat64Number v = 0; + cmsUInt32Number i, start = 0; + + Stride /= PixelSize(info->OutputFormat); + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsFloat32Number*)output)[(i + start)* Stride] = (cmsFloat32Number)v; + else + ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v; + } + + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number)); + *swap1 = (cmsFloat32Number)v; + } + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsFloat32Number); + else + return output + (nChan + Extra) * sizeof(cmsFloat32Number); +} + +static +cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0; + cmsFloat64Number v = 0; + cmsFloat64Number* swap1 = (cmsFloat64Number*)output; + cmsUInt32Number i, start = 0; + + Stride /= PixelSize(info->OutputFormat); + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsFloat64Number*)output)[(i + start) * Stride] = v; + else + ((cmsFloat64Number*)output)[i + start] = v; + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat64Number)); + *swap1 = v; + } + + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsFloat64Number); + else + return output + (nChan + Extra) * sizeof(cmsFloat64Number); + +} + + + + + +static +cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Out = (cmsFloat32Number*) output; + + if (T_PLANAR(Info -> OutputFormat)) { + + Stride /= PixelSize(Info->OutputFormat); + + Out[0] = (cmsFloat32Number) (wOut[0] * 100.0); + Out[Stride] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0); + Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0); + + return output + sizeof(cmsFloat32Number); + } + else { + + Out[0] = (cmsFloat32Number) (wOut[0] * 100.0); + Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0); + Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0); + + return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + } + +} + + +static +cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Out = (cmsFloat64Number*) output; + + if (T_PLANAR(Info -> OutputFormat)) { + + Stride /= PixelSize(Info->OutputFormat); + + Out[0] = (cmsFloat64Number) (wOut[0] * 100.0); + Out[Stride] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0); + Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0); + + return output + sizeof(cmsFloat64Number); + } + else { + + Out[0] = (cmsFloat64Number) (wOut[0] * 100.0); + Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0); + Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0); + + return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + } + +} + + +// From 0..1 range to 0..MAX_ENCODEABLE_XYZ +static +cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsFloat32Number* Out = (cmsFloat32Number*) output; + + if (T_PLANAR(Info -> OutputFormat)) { + + Stride /= PixelSize(Info->OutputFormat); + + Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + Out[Stride] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ); + Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ); + + return output + sizeof(cmsFloat32Number); + } + else { + + Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ); + Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ); + + return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + } + +} + +// Same, but convert to double +static +cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsFloat64Number* Out = (cmsFloat64Number*) output; + + if (T_PLANAR(Info -> OutputFormat)) { + + Stride /= PixelSize(Info->OutputFormat); + + Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + Out[Stride] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ); + Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ); + + return output + sizeof(cmsFloat64Number); + } + else { + + Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ); + Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ); + + return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + } + +} + + +// ---------------------------------------------------------------------------------------------------------------- + +#ifndef CMS_NO_HALF_SUPPORT + +// Decodes an stream of half floats to wIn[] described by input format + +static +cmsUInt8Number* UnrollHalfTo16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + cmsUInt32Number i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F; + + + Stride /= PixelSize(info->OutputFormat); + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] ); + else + v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ; + + if (Reverse) v = maximum - v; + + wIn[index] = _cmsQuickSaturateWord((cmsFloat64Number) v * maximum); + } + + + if (Extra == 0 && SwapFirst) { + cmsUInt16Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number)); + wIn[nChan-1] = tmp; + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsUInt16Number); + else + return accum + (nChan + Extra) * sizeof(cmsUInt16Number); +} + +// Decodes an stream of half floats to wIn[] described by input format + +static +cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + cmsUInt32Number i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; + + Stride /= PixelSize(info->OutputFormat); + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] ); + else + v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ; + + v /= maximum; + + wIn[index] = Reverse ? 1 - v : v; + } + + + if (Extra == 0 && SwapFirst) { + cmsFloat32Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number)); + wIn[nChan-1] = tmp; + } + + if (T_PLANAR(info -> InputFormat)) + return accum + sizeof(cmsUInt16Number); + else + return accum + (nChan + Extra) * sizeof(cmsUInt16Number); +} + + +static +cmsUInt8Number* PackHalfFrom16(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 655.35F : 65535.0F; + cmsFloat32Number v = 0; + cmsUInt16Number* swap1 = (cmsUInt16Number*)output; + cmsUInt32Number i, start = 0; + + Stride /= PixelSize(info->OutputFormat); + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = (cmsFloat32Number)wOut[index] / maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsUInt16Number*)output)[(i + start) * Stride] = _cmsFloat2Half(v); + else + ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v); + } + + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number)); + *swap1 = _cmsFloat2Half(v); + } + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsUInt16Number); + else + return output + (nChan + Extra) * sizeof(cmsUInt16Number); +} + + + +static +cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 100.0F : 1.0F; + cmsUInt16Number* swap1 = (cmsUInt16Number*)output; + cmsFloat32Number v = 0; + cmsUInt32Number i, start = 0; + + Stride /= PixelSize(info->OutputFormat); + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsUInt16Number*)output)[(i + start)* Stride] = _cmsFloat2Half(v); + else + ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v); + } + + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number)); + *swap1 = (cmsUInt16Number)_cmsFloat2Half(v); + } + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsUInt16Number); + else + return output + (nChan + Extra)* sizeof(cmsUInt16Number); +} + +#endif + +// ---------------------------------------------------------------------------------------------------------------- + + +static const cmsFormatters16 InputFormatters16[] = { + + // Type Mask Function + // ---------------------------- ------------------------------------ ---------------------------- + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16}, + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatTo16}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatTo16}, + { TYPE_GRAY_DBL, 0, UnrollDouble1Chan}, + { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| + ANYSWAP|ANYEXTRA|ANYSPACE, UnrollDoubleTo16}, + { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| + ANYSWAP|ANYEXTRA|ANYSPACE, UnrollFloatTo16}, +#ifndef CMS_NO_HALF_SUPPORT + { FLOAT_SH(1)|BYTES_SH(2), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| + ANYEXTRA|ANYSWAP|ANYSPACE, UnrollHalfTo16}, +#endif + + { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Unroll1Byte}, + { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Unroll1ByteSkip1}, + { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2), ANYSPACE, Unroll1ByteSkip2}, + { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll1ByteReversed}, + { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1), 0, Unroll2Bytes}, + + { TYPE_LabV2_8, 0, UnrollLabV2_8 }, + { TYPE_ALabV2_8, 0, UnrollALabV2_8 }, + { TYPE_LabV2_16, 0, UnrollLabV2_16 }, + + { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Unroll3Bytes}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSwap}, + { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSkip1Swap}, + { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3BytesSkip1SwapFirst}, + + { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + ANYSPACE, Unroll3BytesSkip1SwapSwapFirst}, + + { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Unroll4Bytes}, + { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll4BytesReverse}, + { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst}, + + { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST| + ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes}, + + { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes}, + + { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Unroll1Word}, + { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll1WordReversed}, + { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3), ANYSPACE, Unroll1WordSkip3}, + + { CHANNELS_SH(2)|BYTES_SH(2), ANYSPACE, Unroll2Words}, + { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Unroll3Words}, + { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Unroll4Words}, + + { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSwap}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3WordsSkip1SwapFirst}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3WordsSkip1Swap}, + { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll4WordsReverse}, + { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Unroll4WordsSwap}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapSwapFirst}, + + + { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords}, + { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords}, +}; + + + +static const cmsFormattersFloat InputFormattersFloat[] = { + + // Type Mask Function + // ---------------------------- ------------------------------------ ---------------------------- + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleToFloat}, + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatToFloat}, + + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleToFloat}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatToFloat}, + + { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat}, + + { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat}, +#ifndef CMS_NO_HALF_SUPPORT + { FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE, UnrollHalfToFloat}, +#endif +}; + + +// Bit fields set to one in the mask are not compared +static +cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags) +{ + cmsUInt32Number i; + cmsFormatter fr; + + switch (dwFlags) { + + case CMS_PACK_FLAGS_16BITS: { + for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) { + const cmsFormatters16* f = InputFormatters16 + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.Fmt16 = f ->Frm; + return fr; + } + } + } + break; + + case CMS_PACK_FLAGS_FLOAT: { + for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { + const cmsFormattersFloat* f = InputFormattersFloat + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.FmtFloat = f ->Frm; + return fr; + } + } + } + break; + + default:; + + } + + fr.Fmt16 = NULL; + return fr; +} + +static const cmsFormatters16 OutputFormatters16[] = { + // Type Mask Function + // ---------------------------- ------------------------------------ ---------------------------- + + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFrom16}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16}, + + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFrom16}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFrom16}, + + { FLOAT_SH(1)|BYTES_SH(0), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16}, + { FLOAT_SH(1)|BYTES_SH(4), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackFloatFrom16}, +#ifndef CMS_NO_HALF_SUPPORT + { FLOAT_SH(1)|BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackHalfFrom16}, +#endif + + { CHANNELS_SH(1)|BYTES_SH(1), ANYSPACE, Pack1Byte}, + { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack1ByteSkip1}, + { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1ByteSkip1SwapFirst}, + + { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack1ByteReversed}, + + { TYPE_LabV2_8, 0, PackLabV2_8 }, + { TYPE_ALabV2_8, 0, PackALabV2_8 }, + { TYPE_LabV2_16, 0, PackLabV2_16 }, + + { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesOptimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesAndSkip1Optimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), + ANYSPACE, Pack3BytesAndSkip1SwapFirstOptimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1), + ANYSPACE, Pack3BytesAndSkip1SwapSwapFirstOptimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1), + ANYSPACE, Pack3BytesAndSkip1SwapOptimized}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1), ANYSPACE, Pack3BytesSwapOptimized}, + + + + { CHANNELS_SH(3)|BYTES_SH(1), ANYSPACE, Pack3Bytes}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3BytesAndSkip1SwapFirst}, + { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + ANYSPACE, Pack3BytesAndSkip1SwapSwapFirst}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1Swap}, + { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3BytesSwap}, + { CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes}, + { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap}, + { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Pack4Bytes}, + { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack4BytesReverse}, + { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap}, + { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst}, + + { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes}, + { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes}, + + { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word}, + { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1}, + { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack1WordSkip1SwapFirst}, + { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack1WordReversed}, + { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack1WordBigEndian}, + { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Pack3Words}, + { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack3WordsSwap}, + { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack3WordsBigEndian}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack3WordsAndSkip1}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3WordsAndSkip1Swap}, + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack3WordsAndSkip1SwapFirst}, + + { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + ANYSPACE, Pack3WordsAndSkip1SwapSwapFirst}, + + { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Pack4Words}, + { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Pack4WordsReverse}, + { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack4WordsSwap}, + { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1), ANYSPACE, Pack4WordsBigEndian}, + + { CHANNELS_SH(6)|BYTES_SH(2), ANYSPACE, Pack6Words}, + { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack6WordsSwap}, + + { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords}, + { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords} + +}; + + +static const cmsFormattersFloat OutputFormattersFloat[] = { + // Type Mask Function + // ---------------------------- --------------------------------------------------- ---------------------------- + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFromFloat}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFromFloat}, + + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFromFloat}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFromFloat}, + + { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR| + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackFloatsFromFloat }, + { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR| + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackDoublesFromFloat }, +#ifndef CMS_NO_HALF_SUPPORT + { FLOAT_SH(1)|BYTES_SH(2), + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackHalfFromFloat }, +#endif + +}; + + +// Bit fields set to one in the mask are not compared +static +cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags) +{ + cmsUInt32Number i; + cmsFormatter fr; + + // Optimization is only a hint + dwInput &= ~OPTIMIZED_SH(1); + + switch (dwFlags) + { + + case CMS_PACK_FLAGS_16BITS: { + + for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) { + const cmsFormatters16* f = OutputFormatters16 + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.Fmt16 = f ->Frm; + return fr; + } + } + } + break; + + case CMS_PACK_FLAGS_FLOAT: { + + for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { + const cmsFormattersFloat* f = OutputFormattersFloat + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.FmtFloat = f ->Frm; + return fr; + } + } + } + break; + + default:; + + } + + fr.Fmt16 = NULL; + return fr; +} + + +typedef struct _cms_formatters_factory_list { + + cmsFormatterFactory Factory; + struct _cms_formatters_factory_list *Next; + +} cmsFormattersFactoryList; + +_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupFormatterFactoryList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsFormattersPluginChunkType newHead = { NULL }; + cmsFormattersFactoryList* entry; + cmsFormattersFactoryList* Anterior = NULL; + _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->FactoryList; + entry != NULL; + entry = entry ->Next) { + + cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.FactoryList == NULL) + newHead.FactoryList = newEntry; + } + + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType)); +} + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate the LIST + DupFormatterFactoryList(ctx, src); + } + else { + static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL }; + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType)); + } +} + + + +// Formatters management +cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); + cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; + cmsFormattersFactoryList* fl ; + + // Reset to built-in defaults + if (Data == NULL) { + + ctx ->FactoryList = NULL; + return TRUE; + } + + fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList)); + if (fl == NULL) return FALSE; + + fl ->Factory = Plugin ->FormattersFactory; + + fl ->Next = ctx -> FactoryList; + ctx ->FactoryList = fl; + + return TRUE; +} + +cmsFormatter CMSEXPORT _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags) +{ + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); + cmsFormattersFactoryList* f; + + for (f =ctx->FactoryList; f != NULL; f = f ->Next) { + + cmsFormatter fn = f ->Factory(Type, Dir, dwFlags); + if (fn.Fmt16 != NULL) return fn; + } + + // Revert to default + if (Dir == cmsFormatterInput) + return _cmsGetStockInputFormatter(Type, dwFlags); + else + return _cmsGetStockOutputFormatter(Type, dwFlags); +} + + +// Return whatever given formatter refers to float values +cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type) +{ + return T_FLOAT(Type) ? TRUE : FALSE; +} + +// Return whatever given formatter refers to 8 bits +cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type) +{ + cmsUInt32Number Bytes = T_BYTES(Type); + + return (Bytes == 1); +} + +// Build a suitable formatter for the colorspace of this profile +cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat) +{ + + cmsColorSpaceSignature ColorSpace = cmsGetColorSpace(hProfile); + cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace); + cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); + cmsUInt32Number Float = lIsFloat ? 1U : 0; + + // Create a fake formatter for result + return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); +} + +// Build a suitable formatter for the colorspace of this profile +cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat) +{ + + cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); + + cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace); + cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); + cmsUInt32Number Float = lIsFloat ? 1U : 0; + + // Create a fake formatter for result + return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); +} + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmspcs.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmspcs.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmspcs.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmspcs.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,969 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// inter PCS conversions XYZ <-> CIE L* a* b* +/* + + + CIE 15:2004 CIELab is defined as: + + L* = 116*f(Y/Yn) - 16 0 <= L* <= 100 + a* = 500*[f(X/Xn) - f(Y/Yn)] + b* = 200*[f(Y/Yn) - f(Z/Zn)] + + and + + f(t) = t^(1/3) 1 >= t > (24/116)^3 + (841/108)*t + (16/116) 0 <= t <= (24/116)^3 + + + Reverse transform is: + + X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > (24/116) + = Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= (24/116) + + + + PCS in Lab2 is encoded as: + + 8 bit Lab PCS: + + L* 0..100 into a 0..ff byte. + a* t + 128 range is -128.0 +127.0 + b* + + 16 bit Lab PCS: + + L* 0..100 into a 0..ff00 word. + a* t + 128 range is -128.0 +127.9961 + b* + + + +Interchange Space Component Actual Range Encoded Range +CIE XYZ X 0 -> 1.99997 0x0000 -> 0xffff +CIE XYZ Y 0 -> 1.99997 0x0000 -> 0xffff +CIE XYZ Z 0 -> 1.99997 0x0000 -> 0xffff + +Version 2,3 +----------- + +CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xff00 +CIELAB (16 bit) a* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff +CIELAB (16 bit) b* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff + + +Version 4 +--------- + +CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff +CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff +CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff + +*/ + +// Conversions +void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source) +{ + cmsFloat64Number ISum; + + ISum = 1./(Source -> X + Source -> Y + Source -> Z); + + Dest -> x = (Source -> X) * ISum; + Dest -> y = (Source -> Y) * ISum; + Dest -> Y = Source -> Y; +} + +void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source) +{ + Dest -> X = (Source -> x / Source -> y) * Source -> Y; + Dest -> Y = Source -> Y; + Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y; +} + +/* + The break point (24/116)^3 = (6/29)^3 is a very small amount of tristimulus + primary (0.008856). Generally, this only happens for + nearly ideal blacks and for some orange / amber colors in transmission mode. + For example, the Z value of the orange turn indicator lamp lens on an + automobile will often be below this value. But the Z does not + contribute to the perceived color directly. +*/ + +static +cmsFloat64Number f(cmsFloat64Number t) +{ + const cmsFloat64Number Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0); + + if (t <= Limit) + return (841.0/108.0) * t + (16.0/116.0); + else + return pow(t, 1.0/3.0); +} + +static +cmsFloat64Number f_1(cmsFloat64Number t) +{ + const cmsFloat64Number Limit = (24.0/116.0); + + if (t <= Limit) { + return (108.0/841.0) * (t - (16.0/116.0)); + } + + return t * t * t; +} + + +// Standard XYZ to Lab. it can handle negative XZY numbers in some cases +void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz) +{ + cmsFloat64Number fx, fy, fz; + + if (WhitePoint == NULL) + WhitePoint = cmsD50_XYZ(); + + fx = f(xyz->X / WhitePoint->X); + fy = f(xyz->Y / WhitePoint->Y); + fz = f(xyz->Z / WhitePoint->Z); + + Lab->L = 116.0*fy - 16.0; + Lab->a = 500.0*(fx - fy); + Lab->b = 200.0*(fy - fz); +} + + +// Standard XYZ to Lab. It can return negative XYZ in some cases +void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab) +{ + cmsFloat64Number x, y, z; + + if (WhitePoint == NULL) + WhitePoint = cmsD50_XYZ(); + + y = (Lab-> L + 16.0) / 116.0; + x = y + 0.002 * Lab -> a; + z = y - 0.005 * Lab -> b; + + xyz -> X = f_1(x) * WhitePoint -> X; + xyz -> Y = f_1(y) * WhitePoint -> Y; + xyz -> Z = f_1(z) * WhitePoint -> Z; + +} + +static +cmsFloat64Number L2float2(cmsUInt16Number v) +{ + return (cmsFloat64Number) v / 652.800; +} + +// the a/b part +static +cmsFloat64Number ab2float2(cmsUInt16Number v) +{ + return ((cmsFloat64Number) v / 256.0) - 128.0; +} + +static +cmsUInt16Number L2Fix2(cmsFloat64Number L) +{ + return _cmsQuickSaturateWord(L * 652.8); +} + +static +cmsUInt16Number ab2Fix2(cmsFloat64Number ab) +{ + return _cmsQuickSaturateWord((ab + 128.0) * 256.0); +} + + +static +cmsFloat64Number L2float4(cmsUInt16Number v) +{ + return (cmsFloat64Number) v / 655.35; +} + +// the a/b part +static +cmsFloat64Number ab2float4(cmsUInt16Number v) +{ + return ((cmsFloat64Number) v / 257.0) - 128.0; +} + + +void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3]) +{ + Lab->L = L2float2(wLab[0]); + Lab->a = ab2float2(wLab[1]); + Lab->b = ab2float2(wLab[2]); +} + + +void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3]) +{ + Lab->L = L2float4(wLab[0]); + Lab->a = ab2float4(wLab[1]); + Lab->b = ab2float4(wLab[2]); +} + +static +cmsFloat64Number Clamp_L_doubleV2(cmsFloat64Number L) +{ + const cmsFloat64Number L_max = (cmsFloat64Number) (0xFFFF * 100.0) / 0xFF00; + + if (L < 0) L = 0; + if (L > L_max) L = L_max; + + return L; +} + + +static +cmsFloat64Number Clamp_ab_doubleV2(cmsFloat64Number ab) +{ + if (ab < MIN_ENCODEABLE_ab2) ab = MIN_ENCODEABLE_ab2; + if (ab > MAX_ENCODEABLE_ab2) ab = MAX_ENCODEABLE_ab2; + + return ab; +} + +void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* fLab) +{ + cmsCIELab Lab; + + Lab.L = Clamp_L_doubleV2(fLab ->L); + Lab.a = Clamp_ab_doubleV2(fLab ->a); + Lab.b = Clamp_ab_doubleV2(fLab ->b); + + wLab[0] = L2Fix2(Lab.L); + wLab[1] = ab2Fix2(Lab.a); + wLab[2] = ab2Fix2(Lab.b); +} + + +static +cmsFloat64Number Clamp_L_doubleV4(cmsFloat64Number L) +{ + if (L < 0) L = 0; + if (L > 100.0) L = 100.0; + + return L; +} + +static +cmsFloat64Number Clamp_ab_doubleV4(cmsFloat64Number ab) +{ + if (ab < MIN_ENCODEABLE_ab4) ab = MIN_ENCODEABLE_ab4; + if (ab > MAX_ENCODEABLE_ab4) ab = MAX_ENCODEABLE_ab4; + + return ab; +} + +static +cmsUInt16Number L2Fix4(cmsFloat64Number L) +{ + return _cmsQuickSaturateWord(L * 655.35); +} + +static +cmsUInt16Number ab2Fix4(cmsFloat64Number ab) +{ + return _cmsQuickSaturateWord((ab + 128.0) * 257.0); +} + +void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLab) +{ + cmsCIELab Lab; + + Lab.L = Clamp_L_doubleV4(fLab ->L); + Lab.a = Clamp_ab_doubleV4(fLab ->a); + Lab.b = Clamp_ab_doubleV4(fLab ->b); + + wLab[0] = L2Fix4(Lab.L); + wLab[1] = ab2Fix4(Lab.a); + wLab[2] = ab2Fix4(Lab.b); +} + +// Auxiliary: convert to Radians +static +cmsFloat64Number RADIANS(cmsFloat64Number deg) +{ + return (deg * M_PI) / 180.; +} + + +// Auxiliary: atan2 but operating in degrees and returning 0 if a==b==0 +static +cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b) +{ + cmsFloat64Number h; + + if (a == 0 && b == 0) + h = 0; + else + h = atan2(a, b); + + h *= (180. / M_PI); + + while (h > 360.) + h -= 360.; + + while ( h < 0) + h += 360.; + + return h; +} + + +// Auxiliary: Square +static +cmsFloat64Number Sqr(cmsFloat64Number v) +{ + return v * v; +} +// From cylindrical coordinates. No check is performed, then negative values are allowed +void CMSEXPORT cmsLab2LCh(cmsCIELCh* LCh, const cmsCIELab* Lab) +{ + LCh -> L = Lab -> L; + LCh -> C = pow(Sqr(Lab ->a) + Sqr(Lab ->b), 0.5); + LCh -> h = atan2deg(Lab ->b, Lab ->a); +} + + +// To cylindrical coordinates. No check is performed, then negative values are allowed +void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh) +{ + cmsFloat64Number h = (LCh -> h * M_PI) / 180.0; + + Lab -> L = LCh -> L; + Lab -> a = LCh -> C * cos(h); + Lab -> b = LCh -> C * sin(h); +} + +// In XYZ All 3 components are encoded using 1.15 fixed point +static +cmsUInt16Number XYZ2Fix(cmsFloat64Number d) +{ + return _cmsQuickSaturateWord(d * 32768.0); +} + +void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ) +{ + cmsCIEXYZ xyz; + + xyz.X = fXYZ -> X; + xyz.Y = fXYZ -> Y; + xyz.Z = fXYZ -> Z; + + // Clamp to encodeable values. + if (xyz.Y <= 0) { + + xyz.X = 0; + xyz.Y = 0; + xyz.Z = 0; + } + + if (xyz.X > MAX_ENCODEABLE_XYZ) + xyz.X = MAX_ENCODEABLE_XYZ; + + if (xyz.X < 0) + xyz.X = 0; + + if (xyz.Y > MAX_ENCODEABLE_XYZ) + xyz.Y = MAX_ENCODEABLE_XYZ; + + if (xyz.Y < 0) + xyz.Y = 0; + + if (xyz.Z > MAX_ENCODEABLE_XYZ) + xyz.Z = MAX_ENCODEABLE_XYZ; + + if (xyz.Z < 0) + xyz.Z = 0; + + + XYZ[0] = XYZ2Fix(xyz.X); + XYZ[1] = XYZ2Fix(xyz.Y); + XYZ[2] = XYZ2Fix(xyz.Z); +} + + +// To convert from Fixed 1.15 point to cmsFloat64Number +static +cmsFloat64Number XYZ2float(cmsUInt16Number v) +{ + cmsS15Fixed16Number fix32; + + // From 1.15 to 15.16 + fix32 = v << 1; + + // From fixed 15.16 to cmsFloat64Number + return _cms15Fixed16toDouble(fix32); +} + + +void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fXYZ, const cmsUInt16Number XYZ[3]) +{ + fXYZ -> X = XYZ2float(XYZ[0]); + fXYZ -> Y = XYZ2float(XYZ[1]); + fXYZ -> Z = XYZ2float(XYZ[2]); +} + + +// Returns dE on two Lab values +cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) +{ + cmsFloat64Number dL, da, db; + + dL = fabs(Lab1 -> L - Lab2 -> L); + da = fabs(Lab1 -> a - Lab2 -> a); + db = fabs(Lab1 -> b - Lab2 -> b); + + return pow(Sqr(dL) + Sqr(da) + Sqr(db), 0.5); +} + + +// Return the CIE94 Delta E +cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) +{ + cmsCIELCh LCh1, LCh2; + cmsFloat64Number dE, dL, dC, dh, dhsq; + cmsFloat64Number c12, sc, sh; + + dL = fabs(Lab1 ->L - Lab2 ->L); + + cmsLab2LCh(&LCh1, Lab1); + cmsLab2LCh(&LCh2, Lab2); + + dC = fabs(LCh1.C - LCh2.C); + dE = cmsDeltaE(Lab1, Lab2); + + dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC); + if (dhsq < 0) + dh = 0; + else + dh = pow(dhsq, 0.5); + + c12 = sqrt(LCh1.C * LCh2.C); + + sc = 1.0 + (0.048 * c12); + sh = 1.0 + (0.014 * c12); + + return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh)); +} + + +// Auxiliary +static +cmsFloat64Number ComputeLBFD(const cmsCIELab* Lab) +{ + cmsFloat64Number yt; + + if (Lab->L > 7.996969) + yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100; + else + yt = 100 * (Lab->L / 903.3); + + return (54.6 * (M_LOG10E * (log(yt + 1.5))) - 9.6); +} + + + +// bfd - gets BFD(1:1) difference between Lab1, Lab2 +cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) +{ + cmsFloat64Number lbfd1,lbfd2,AveC,Aveh,dE,deltaL, + deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd; + cmsCIELCh LCh1, LCh2; + + + lbfd1 = ComputeLBFD(Lab1); + lbfd2 = ComputeLBFD(Lab2); + deltaL = lbfd2 - lbfd1; + + cmsLab2LCh(&LCh1, Lab1); + cmsLab2LCh(&LCh2, Lab2); + + deltaC = LCh2.C - LCh1.C; + AveC = (LCh1.C+LCh2.C)/2; + Aveh = (LCh1.h+LCh2.h)/2; + + dE = cmsDeltaE(Lab1, Lab2); + + if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC))) + deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC)); + else + deltah =0; + + + dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521; + g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000)); + t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))- + 0.040*cos((2*Aveh-136)/(180/M_PI))+ + 0.070*cos((3*Aveh-31)/(180/M_PI))+ + 0.049*cos((4*Aveh+114)/(180/M_PI))- + 0.015*cos((5*Aveh-103)/(180/M_PI))); + + dh = dc*(g*t+1-g); + rh = -0.260*cos((Aveh-308)/(180/M_PI))- + 0.379*cos((2*Aveh-160)/(180/M_PI))- + 0.636*cos((3*Aveh+254)/(180/M_PI))+ + 0.226*cos((4*Aveh+140)/(180/M_PI))- + 0.194*cos((5*Aveh+280)/(180/M_PI)); + + rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000)); + rt = rh*rc; + + bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh))); + + return bfd; +} + + +// cmc - CMC(l:c) difference between Lab1, Lab2 +cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c) +{ + cmsFloat64Number dE,dL,dC,dh,sl,sc,sh,t,f,cmc; + cmsCIELCh LCh1, LCh2; + + if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0; + + cmsLab2LCh(&LCh1, Lab1); + cmsLab2LCh(&LCh2, Lab2); + + + dL = Lab2->L-Lab1->L; + dC = LCh2.C-LCh1.C; + + dE = cmsDeltaE(Lab1, Lab2); + + if (Sqr(dE)>(Sqr(dL)+Sqr(dC))) + dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC)); + else + dh =0; + + if ((LCh1.h > 164) && (LCh1.h < 345)) + t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI)))); + else + t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI)))); + + sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638; + sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L); + + if (Lab1->L<16) + sl = 0.511; + + f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900)); + sh = sc*(t*f+1-f); + cmc = sqrt(Sqr(dL/(l*sl))+Sqr(dC/(c*sc))+Sqr(dh/sh)); + + return cmc; +} + +// dE2000 The weightings KL, KC and KH can be modified to reflect the relative +// importance of lightness, chroma and hue in different industrial applications +cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, + cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh) +{ + cmsFloat64Number L1 = Lab1->L; + cmsFloat64Number a1 = Lab1->a; + cmsFloat64Number b1 = Lab1->b; + cmsFloat64Number C = sqrt( Sqr(a1) + Sqr(b1) ); + + cmsFloat64Number Ls = Lab2 ->L; + cmsFloat64Number as = Lab2 ->a; + cmsFloat64Number bs = Lab2 ->b; + cmsFloat64Number Cs = sqrt( Sqr(as) + Sqr(bs) ); + + cmsFloat64Number G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) )); + + cmsFloat64Number a_p = (1 + G ) * a1; + cmsFloat64Number b_p = b1; + cmsFloat64Number C_p = sqrt( Sqr(a_p) + Sqr(b_p)); + cmsFloat64Number h_p = atan2deg(b_p, a_p); + + + cmsFloat64Number a_ps = (1 + G) * as; + cmsFloat64Number b_ps = bs; + cmsFloat64Number C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps)); + cmsFloat64Number h_ps = atan2deg(b_ps, a_ps); + + cmsFloat64Number meanC_p =(C_p + C_ps) / 2; + + cmsFloat64Number hps_plus_hp = h_ps + h_p; + cmsFloat64Number hps_minus_hp = h_ps - h_p; + + cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 : + (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 : + (hps_plus_hp - 360)/2; + + cmsFloat64Number delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) : + (hps_minus_hp) > 180 ? (hps_minus_hp - 360) : + (hps_minus_hp); + cmsFloat64Number delta_L = (Ls - L1); + cmsFloat64Number delta_C = (C_ps - C_p ); + + + cmsFloat64Number delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANS(delta_h) / 2); + + cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30)) + + 0.24 * cos(RADIANS(2*meanh_p)) + + 0.32 * cos(RADIANS(3*meanh_p + 6)) + - 0.2 * cos(RADIANS(4*meanh_p - 63)); + + cmsFloat64Number Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) ); + + cmsFloat64Number Sc = 1 + 0.045 * (C_p + C_ps)/2; + cmsFloat64Number Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T; + + cmsFloat64Number delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25))); + + cmsFloat64Number Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0))); + + cmsFloat64Number Rt = -sin(2 * RADIANS(delta_ro)) * Rc; + + cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) + + Sqr(delta_C/(Sc * Kc)) + + Sqr(delta_H/(Sh * Kh)) + + Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh))); + + return deltaE00; +} + +// This function returns a number of gridpoints to be used as LUT table. It assumes same number +// of gripdpoints in all dimensions. Flags may override the choice. +cmsUInt32Number CMSEXPORT _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags) +{ + cmsUInt32Number nChannels; + + // Already specified? + if (dwFlags & 0x00FF0000) { + // Yes, grab'em + return (dwFlags >> 16) & 0xFF; + } + + nChannels = cmsChannelsOf(Colorspace); + + // HighResPrecalc is maximum resolution + if (dwFlags & cmsFLAGS_HIGHRESPRECALC) { + + if (nChannels > 4) + return 7; // 7 for Hifi + + if (nChannels == 4) // 23 for CMYK + return 23; + + return 49; // 49 for RGB and others + } + + + // LowResPrecal is lower resolution + if (dwFlags & cmsFLAGS_LOWRESPRECALC) { + + if (nChannels > 4) + return 6; // 6 for more than 4 channels + + if (nChannels == 1) + return 33; // For monochrome + + return 17; // 17 for remaining + } + + // Default values + if (nChannels > 4) + return 7; // 7 for Hifi + + if (nChannels == 4) + return 17; // 17 for CMYK + + return 33; // 33 for RGB +} + + +cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, + cmsUInt16Number **White, + cmsUInt16Number **Black, + cmsUInt32Number *nOutputs) +{ + // Only most common spaces + + static cmsUInt16Number RGBblack[4] = { 0, 0, 0 }; + static cmsUInt16Number RGBwhite[4] = { 0xffff, 0xffff, 0xffff }; + static cmsUInt16Number CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff }; // 400% of ink + static cmsUInt16Number CMYKwhite[4] = { 0, 0, 0, 0 }; + static cmsUInt16Number LABblack[4] = { 0, 0x8080, 0x8080 }; // V4 Lab encoding + static cmsUInt16Number LABwhite[4] = { 0xFFFF, 0x8080, 0x8080 }; + static cmsUInt16Number CMYblack[4] = { 0xffff, 0xffff, 0xffff }; + static cmsUInt16Number CMYwhite[4] = { 0, 0, 0 }; + static cmsUInt16Number Grayblack[4] = { 0 }; + static cmsUInt16Number GrayWhite[4] = { 0xffff }; + + switch (Space) { + + case cmsSigGrayData: if (White) *White = GrayWhite; + if (Black) *Black = Grayblack; + if (nOutputs) *nOutputs = 1; + return TRUE; + + case cmsSigRgbData: if (White) *White = RGBwhite; + if (Black) *Black = RGBblack; + if (nOutputs) *nOutputs = 3; + return TRUE; + + case cmsSigLabData: if (White) *White = LABwhite; + if (Black) *Black = LABblack; + if (nOutputs) *nOutputs = 3; + return TRUE; + + case cmsSigCmykData: if (White) *White = CMYKwhite; + if (Black) *Black = CMYKblack; + if (nOutputs) *nOutputs = 4; + return TRUE; + + case cmsSigCmyData: if (White) *White = CMYwhite; + if (Black) *Black = CMYblack; + if (nOutputs) *nOutputs = 3; + return TRUE; + + default:; + } + + return FALSE; +} + + + +// Several utilities ------------------------------------------------------- + +// Translate from our colorspace to ICC representation + +cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation) +{ + switch (OurNotation) { + + case 1: + case PT_GRAY: return cmsSigGrayData; + + case 2: + case PT_RGB: return cmsSigRgbData; + + case PT_CMY: return cmsSigCmyData; + case PT_CMYK: return cmsSigCmykData; + case PT_YCbCr:return cmsSigYCbCrData; + case PT_YUV: return cmsSigLuvData; + case PT_XYZ: return cmsSigXYZData; + + case PT_LabV2: + case PT_Lab: return cmsSigLabData; + + case PT_YUVK: return cmsSigLuvKData; + case PT_HSV: return cmsSigHsvData; + case PT_HLS: return cmsSigHlsData; + case PT_Yxy: return cmsSigYxyData; + + case PT_MCH1: return cmsSigMCH1Data; + case PT_MCH2: return cmsSigMCH2Data; + case PT_MCH3: return cmsSigMCH3Data; + case PT_MCH4: return cmsSigMCH4Data; + case PT_MCH5: return cmsSigMCH5Data; + case PT_MCH6: return cmsSigMCH6Data; + case PT_MCH7: return cmsSigMCH7Data; + case PT_MCH8: return cmsSigMCH8Data; + + case PT_MCH9: return cmsSigMCH9Data; + case PT_MCH10: return cmsSigMCHAData; + case PT_MCH11: return cmsSigMCHBData; + case PT_MCH12: return cmsSigMCHCData; + case PT_MCH13: return cmsSigMCHDData; + case PT_MCH14: return cmsSigMCHEData; + case PT_MCH15: return cmsSigMCHFData; + + default: return (cmsColorSpaceSignature) 0; + } +} + + +int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace) +{ + switch (ProfileSpace) { + + case cmsSigGrayData: return PT_GRAY; + case cmsSigRgbData: return PT_RGB; + case cmsSigCmyData: return PT_CMY; + case cmsSigCmykData: return PT_CMYK; + case cmsSigYCbCrData:return PT_YCbCr; + case cmsSigLuvData: return PT_YUV; + case cmsSigXYZData: return PT_XYZ; + case cmsSigLabData: return PT_Lab; + case cmsSigLuvKData: return PT_YUVK; + case cmsSigHsvData: return PT_HSV; + case cmsSigHlsData: return PT_HLS; + case cmsSigYxyData: return PT_Yxy; + + case cmsSig1colorData: + case cmsSigMCH1Data: return PT_MCH1; + + case cmsSig2colorData: + case cmsSigMCH2Data: return PT_MCH2; + + case cmsSig3colorData: + case cmsSigMCH3Data: return PT_MCH3; + + case cmsSig4colorData: + case cmsSigMCH4Data: return PT_MCH4; + + case cmsSig5colorData: + case cmsSigMCH5Data: return PT_MCH5; + + case cmsSig6colorData: + case cmsSigMCH6Data: return PT_MCH6; + + case cmsSigMCH7Data: + case cmsSig7colorData:return PT_MCH7; + + case cmsSigMCH8Data: + case cmsSig8colorData:return PT_MCH8; + + case cmsSigMCH9Data: + case cmsSig9colorData:return PT_MCH9; + + case cmsSigMCHAData: + case cmsSig10colorData:return PT_MCH10; + + case cmsSigMCHBData: + case cmsSig11colorData:return PT_MCH11; + + case cmsSigMCHCData: + case cmsSig12colorData:return PT_MCH12; + + case cmsSigMCHDData: + case cmsSig13colorData:return PT_MCH13; + + case cmsSigMCHEData: + case cmsSig14colorData:return PT_MCH14; + + case cmsSigMCHFData: + case cmsSig15colorData:return PT_MCH15; + + default: return (cmsColorSpaceSignature) 0; + } +} + + +cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) +{ + switch (ColorSpace) { + + case cmsSigMCH1Data: + case cmsSig1colorData: + case cmsSigGrayData: return 1; + + case cmsSigMCH2Data: + case cmsSig2colorData: return 2; + + case cmsSigXYZData: + case cmsSigLabData: + case cmsSigLuvData: + case cmsSigYCbCrData: + case cmsSigYxyData: + case cmsSigRgbData: + case cmsSigHsvData: + case cmsSigHlsData: + case cmsSigCmyData: + case cmsSigMCH3Data: + case cmsSig3colorData: return 3; + + case cmsSigLuvKData: + case cmsSigCmykData: + case cmsSigMCH4Data: + case cmsSig4colorData: return 4; + + case cmsSigMCH5Data: + case cmsSig5colorData: return 5; + + case cmsSigMCH6Data: + case cmsSig6colorData: return 6; + + case cmsSigMCH7Data: + case cmsSig7colorData: return 7; + + case cmsSigMCH8Data: + case cmsSig8colorData: return 8; + + case cmsSigMCH9Data: + case cmsSig9colorData: return 9; + + case cmsSigMCHAData: + case cmsSig10colorData: return 10; + + case cmsSigMCHBData: + case cmsSig11colorData: return 11; + + case cmsSigMCHCData: + case cmsSig12colorData: return 12; + + case cmsSigMCHDData: + case cmsSig13colorData: return 13; + + case cmsSigMCHEData: + case cmsSig14colorData: return 14; + + case cmsSigMCHFData: + case cmsSig15colorData: return 15; + + default: return 3; + } +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsplugin.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsplugin.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsplugin.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsplugin.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1020 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// ---------------------------------------------------------------------------------- +// Encoding & Decoding support functions +// ---------------------------------------------------------------------------------- + +// Little-Endian to Big-Endian + +// Adjust a word value after being read/ before being written from/to an ICC profile +cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word) +{ +#ifndef CMS_USE_BIG_ENDIAN + + cmsUInt8Number* pByte = (cmsUInt8Number*) &Word; + cmsUInt8Number tmp; + + tmp = pByte[0]; + pByte[0] = pByte[1]; + pByte[1] = tmp; +#endif + + return Word; +} + + +// Transports to properly encoded values - note that icc profiles does use big endian notation. + +// 1 2 3 4 +// 4 3 2 1 + +cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord) +{ +#ifndef CMS_USE_BIG_ENDIAN + + cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord; + cmsUInt8Number temp1; + cmsUInt8Number temp2; + + temp1 = *pByte++; + temp2 = *pByte++; + *(pByte-1) = *pByte; + *pByte++ = temp2; + *(pByte-3) = *pByte; + *pByte = temp1; +#endif + return DWord; +} + +// 1 2 3 4 5 6 7 8 +// 8 7 6 5 4 3 2 1 + +void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord) +{ + +#ifndef CMS_USE_BIG_ENDIAN + + cmsUInt8Number* pIn = (cmsUInt8Number*) QWord; + cmsUInt8Number* pOut = (cmsUInt8Number*) Result; + + _cmsAssert(Result != NULL); + + pOut[7] = pIn[0]; + pOut[6] = pIn[1]; + pOut[5] = pIn[2]; + pOut[4] = pIn[3]; + pOut[3] = pIn[4]; + pOut[2] = pIn[5]; + pOut[1] = pIn[6]; + pOut[0] = pIn[7]; + +#else + _cmsAssert(Result != NULL); + +# ifdef CMS_DONT_USE_INT64 + (*Result)[0] = (*QWord)[0]; + (*Result)[1] = (*QWord)[1]; +# else + *Result = *QWord; +# endif +#endif +} + +// Auxiliary -- read 8, 16 and 32-bit numbers +cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n) +{ + cmsUInt8Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1) + return FALSE; + + if (n != NULL) *n = tmp; + return TRUE; +} + +cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n) +{ + cmsUInt16Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1) + return FALSE; + + if (n != NULL) *n = _cmsAdjustEndianess16(tmp); + return TRUE; +} + +cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array) +{ + cmsUInt32Number i; + + _cmsAssert(io != NULL); + + for (i=0; i < n; i++) { + + if (Array != NULL) { + if (!_cmsReadUInt16Number(io, Array + i)) return FALSE; + } + else { + if (!_cmsReadUInt16Number(io, NULL)) return FALSE; + } + + } + return TRUE; +} + +cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) + return FALSE; + + if (n != NULL) *n = _cmsAdjustEndianess32(tmp); + return TRUE; +} + +cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + if (io->Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) + return FALSE; + + if (n != NULL) { + + tmp = _cmsAdjustEndianess32(tmp); + *n = *(cmsFloat32Number*)(void*)&tmp; + + // Safeguard which covers against absurd values + if (*n > 1E+20 || *n < -1E+20) return FALSE; + + #if defined(_MSC_VER) && _MSC_VER < 1800 + return TRUE; + #elif defined (__BORLANDC__) + return TRUE; + #elif !defined(_MSC_VER) && (defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L) + return TRUE; + #else + + // fpclassify() required by C99 (only provided by MSVC >= 1800, VS2013 onwards) + return ((fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL)); + #endif + } + + return TRUE; +} + + +cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) +{ + cmsUInt64Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1) + return FALSE; + + if (n != NULL) { + + _cmsAdjustEndianess64(n, &tmp); + } + + return TRUE; +} + + +cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) + return FALSE; + + if (n != NULL) { + *n = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32(tmp)); + } + + return TRUE; +} + + +cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ) +{ + cmsEncodedXYZNumber xyz; + + _cmsAssert(io != NULL); + + if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE; + + if (XYZ != NULL) { + + XYZ->X = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.X)); + XYZ->Y = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Y)); + XYZ->Z = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Z)); + } + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n) +{ + _cmsAssert(io != NULL); + + if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n) +{ + cmsUInt16Number tmp; + + _cmsAssert(io != NULL); + + tmp = _cmsAdjustEndianess16(n); + if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array) +{ + cmsUInt32Number i; + + _cmsAssert(io != NULL); + _cmsAssert(Array != NULL); + + for (i=0; i < n; i++) { + if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE; + } + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + tmp = _cmsAdjustEndianess32(n); + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + + +cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + tmp = *(cmsUInt32Number*) (void*) &n; + tmp = _cmsAdjustEndianess32(tmp); + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) +{ + cmsUInt64Number tmp; + + _cmsAssert(io != NULL); + + _cmsAdjustEndianess64(&tmp, n); + if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n) +{ + cmsUInt32Number tmp; + + _cmsAssert(io != NULL); + + tmp = _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(n)); + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + return FALSE; + + return TRUE; +} + +cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ) +{ + cmsEncodedXYZNumber xyz; + + _cmsAssert(io != NULL); + _cmsAssert(XYZ != NULL); + + xyz.X = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->X)); + xyz.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Y)); + xyz.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Z)); + + return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz); +} + +// from Fixed point 8.8 to double +cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8) +{ + cmsUInt8Number msb, lsb; + + lsb = (cmsUInt8Number) (fixed8 & 0xff); + msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff); + + return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0)); +} + +cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) +{ + cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val); + return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF); +} + +// from Fixed point 15.16 to double +cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32) +{ + cmsFloat64Number floater, sign, mid; + int Whole, FracPart; + + sign = (fix32 < 0 ? -1 : 1); + fix32 = abs(fix32); + + Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff; + FracPart = (cmsUInt16Number)(fix32 & 0xffff); + + mid = (cmsFloat64Number) FracPart / 65536.0; + floater = (cmsFloat64Number) Whole + mid; + + return sign * floater; +} + +// from double to Fixed point 15.16 +cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v) +{ + return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5)); +} + +// Date/Time functions + +void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest) +{ + + _cmsAssert(Dest != NULL); + _cmsAssert(Source != NULL); + + Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds); + Dest->tm_min = _cmsAdjustEndianess16(Source->minutes); + Dest->tm_hour = _cmsAdjustEndianess16(Source->hours); + Dest->tm_mday = _cmsAdjustEndianess16(Source->day); + Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1; + Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900; + Dest->tm_wday = -1; + Dest->tm_yday = -1; + Dest->tm_isdst = 0; +} + +void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source) +{ + _cmsAssert(Dest != NULL); + _cmsAssert(Source != NULL); + + Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec); + Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min); + Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour); + Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday); + Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1)); + Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900)); +} + +// Read base and return type base +cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io) +{ + _cmsTagBase Base; + + _cmsAssert(io != NULL); + + if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1) + return (cmsTagTypeSignature) 0; + + return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig); +} + +// Setup base marker +cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig) +{ + _cmsTagBase Base; + + _cmsAssert(io != NULL); + + Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig); + memset(&Base.reserved, 0, sizeof(Base.reserved)); + return io -> Write(io, sizeof(_cmsTagBase), &Base); +} + +cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io) +{ + cmsUInt8Number Buffer[4]; + cmsUInt32Number NextAligned, At; + cmsUInt32Number BytesToNextAlignedPos; + + _cmsAssert(io != NULL); + + At = io -> Tell(io); + NextAligned = _cmsALIGNLONG(At); + BytesToNextAlignedPos = NextAligned - At; + if (BytesToNextAlignedPos == 0) return TRUE; + if (BytesToNextAlignedPos > 4) return FALSE; + + return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1); +} + +cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io) +{ + cmsUInt8Number Buffer[4]; + cmsUInt32Number NextAligned, At; + cmsUInt32Number BytesToNextAlignedPos; + + _cmsAssert(io != NULL); + + At = io -> Tell(io); + NextAligned = _cmsALIGNLONG(At); + BytesToNextAlignedPos = NextAligned - At; + if (BytesToNextAlignedPos == 0) return TRUE; + if (BytesToNextAlignedPos > 4) return FALSE; + + memset(Buffer, 0, BytesToNextAlignedPos); + return io -> Write(io, BytesToNextAlignedPos, Buffer); +} + + +// To deal with text streams. 2K at most +cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) +{ + va_list args; + int len; + cmsUInt8Number Buffer[2048]; + cmsBool rc; + cmsUInt8Number* ptr; + + _cmsAssert(io != NULL); + _cmsAssert(frm != NULL); + + va_start(args, frm); + + len = vsnprintf((char*) Buffer, 2047, frm, args); + if (len < 0) { + va_end(args); + return FALSE; // Truncated, which is a fatal error for us + } + + // setlocale may be active, no commas are needed in PS generator + // and PS generator is our only client + for (ptr = Buffer; *ptr; ptr++) + { + if (*ptr == ',') *ptr = '.'; + } + + rc = io ->Write(io, (cmsUInt32Number) len, Buffer); + + va_end(args); + + return rc; +} + + +// Plugin memory management ------------------------------------------------------------------------------------------------- + +// Specialized malloc for plug-ins, that is freed upon exit. +void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size) +{ + struct _cmsContext_struct* ctx = _cmsGetContext(ContextID); + + if (ctx ->MemPool == NULL) { + + if (ContextID == NULL) { + + ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024); + if (ctx->MemPool == NULL) return NULL; + } + else { + cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context"); + return NULL; + } + } + + return _cmsSubAlloc(ctx->MemPool, size); +} + + +// Main plug-in dispatcher +cmsBool CMSEXPORT cmsPlugin(void* Plug_in) +{ + return cmsPluginTHR(NULL, Plug_in); +} + +cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) +{ + cmsPluginBase* Plugin; + + for (Plugin = (cmsPluginBase*) Plug_in; + Plugin != NULL; + Plugin = Plugin -> Next) { + + if (Plugin -> Magic != cmsPluginMagicNumber) { + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); + return FALSE; + } + + if (Plugin ->ExpectedVersion > LCMS_VERSION) { + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", + Plugin ->ExpectedVersion, LCMS_VERSION); + return FALSE; + } + + switch (Plugin -> Type) { + + case cmsPluginMemHandlerSig: + if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginInterpolationSig: + if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginTagTypeSig: + if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginTagSig: + if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginFormattersSig: + if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginRenderingIntentSig: + if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginParametricCurveSig: + if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginMultiProcessElementSig: + if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginOptimizationSig: + if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginTransformSig: + if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE; + break; + + case cmsPluginMutexSig: + if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE; + break; + + default: + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); + return FALSE; + } + } + + // Keep a reference to the plug-in + return TRUE; +} + + +// Revert all plug-ins to default +void CMSEXPORT cmsUnregisterPlugins(void) +{ + cmsUnregisterPluginsTHR(NULL); +} + + +// The Global storage for system context. This is the one and only global variable +// pointers structure. All global vars are referenced here. +static struct _cmsContext_struct globalContext = { + + NULL, // Not in the linked list + NULL, // No suballocator + { + NULL, // UserPtr, + &_cmsLogErrorChunk, // Logger, + &_cmsAlarmCodesChunk, // AlarmCodes, + &_cmsAdaptationStateChunk, // AdaptationState, + &_cmsMemPluginChunk, // MemPlugin, + &_cmsInterpPluginChunk, // InterpPlugin, + &_cmsCurvesPluginChunk, // CurvesPlugin, + &_cmsFormattersPluginChunk, // FormattersPlugin, + &_cmsTagTypePluginChunk, // TagTypePlugin, + &_cmsTagPluginChunk, // TagPlugin, + &_cmsIntentsPluginChunk, // IntentPlugin, + &_cmsMPETypePluginChunk, // MPEPlugin, + &_cmsOptimizationPluginChunk, // OptimizationPlugin, + &_cmsTransformPluginChunk, // TransformPlugin, + &_cmsMutexPluginChunk // MutexPlugin + }, + + { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0 +}; + + +// The context pool (linked list head) +static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER; +static struct _cmsContext_struct* _cmsContextPoolHead = NULL; + +// Internal, get associated pointer, with guessing. Never returns NULL. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) +{ + struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct* ctx; + + + // On 0, use global settings + if (id == NULL) + return &globalContext; + + // Search + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + for (ctx = _cmsContextPoolHead; + ctx != NULL; + ctx = ctx ->Next) { + + // Found it? + if (id == ctx) + { + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + return ctx; // New-style context + } + } + + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + return &globalContext; +} + + +// Internal: get the memory area associanted with each context client +// Returns the block assigned to the specific zone. Never return NULL. +void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) +{ + struct _cmsContext_struct* ctx; + void *ptr; + + if ((int) mc < 0 || mc >= MemoryClientMax) { + + cmsSignalError(ContextID, cmsERROR_INTERNAL, "Bad context client -- possible corruption"); + + // This is catastrophic. Should never reach here + _cmsAssert(0); + + // Reverts to global context + return globalContext.chunks[UserPtr]; + } + + ctx = _cmsGetContext(ContextID); + ptr = ctx ->chunks[mc]; + + if (ptr != NULL) + return ptr; + + // A null ptr means no special settings for that context, and this + // reverts to Context0 globals + return globalContext.chunks[mc]; +} + + +// This function returns the given context its default pristine state, +// as no plug-ins were declared. There is no way to unregister a single +// plug-in, as a single call to cmsPluginTHR() function may register +// many different plug-ins simultaneously, then there is no way to +// identify which plug-in to unregister. +void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) +{ + _cmsRegisterMemHandlerPlugin(ContextID, NULL); + _cmsRegisterInterpPlugin(ContextID, NULL); + _cmsRegisterTagTypePlugin(ContextID, NULL); + _cmsRegisterTagPlugin(ContextID, NULL); + _cmsRegisterFormattersPlugin(ContextID, NULL); + _cmsRegisterRenderingIntentPlugin(ContextID, NULL); + _cmsRegisterParametricCurvesPlugin(ContextID, NULL); + _cmsRegisterMultiProcessElementPlugin(ContextID, NULL); + _cmsRegisterOptimizationPlugin(ContextID, NULL); + _cmsRegisterTransformPlugin(ContextID, NULL); + _cmsRegisterMutexPlugin(ContextID, NULL); +} + + +// Returns the memory manager plug-in, if any, from the Plug-in bundle +static +cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle) +{ + cmsPluginBase* Plugin; + + for (Plugin = (cmsPluginBase*) PluginBundle; + Plugin != NULL; + Plugin = Plugin -> Next) { + + if (Plugin -> Magic == cmsPluginMagicNumber && + Plugin -> ExpectedVersion <= LCMS_VERSION && + Plugin -> Type == cmsPluginMemHandlerSig) { + + // Found! + return (cmsPluginMemHandler*) Plugin; + } + } + + // Nope, revert to defaults + return NULL; +} + + +// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) +{ + struct _cmsContext_struct* ctx; + struct _cmsContext_struct fakeContext; + + // See the comments regarding locking in lcms2_internal.h + // for an explanation of why we need the following code. +#ifndef CMS_NO_PTHREADS +#ifdef CMS_IS_WINDOWS_ +#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT + { + static HANDLE _cmsWindowsInitMutex = NULL; + static volatile HANDLE* mutex = &_cmsWindowsInitMutex; + + if (*mutex == NULL) + { + HANDLE p = CreateMutex(NULL, FALSE, NULL); + if (p && InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL) + CloseHandle(p); + } + if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) + return NULL; + if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL) + InitializeCriticalSection(&_cmsContextPoolHeadMutex); + if (*mutex == NULL || !ReleaseMutex(*mutex)) + return NULL; + } +#endif +#endif +#endif + + _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); + + fakeContext.chunks[UserPtr] = UserData; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Create the context structure. + ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened! + + // Init the structure and the memory manager + memset(ctx, 0, sizeof(struct _cmsContext_struct)); + + // Keep memory manager + memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk)); + + // Maintain the linked list (with proper locking) + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + ctx ->Next = _cmsContextPoolHead; + _cmsContextPoolHead = ctx; + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + ctx ->chunks[UserPtr] = UserData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + // Now we can allocate the pool by using default memory manager + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 22 pointers + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + _cmsAllocLogErrorChunk(ctx, NULL); + _cmsAllocAlarmCodesChunk(ctx, NULL); + _cmsAllocAdaptationStateChunk(ctx, NULL); + _cmsAllocMemPluginChunk(ctx, NULL); + _cmsAllocInterpPluginChunk(ctx, NULL); + _cmsAllocCurvesPluginChunk(ctx, NULL); + _cmsAllocFormattersPluginChunk(ctx, NULL); + _cmsAllocTagTypePluginChunk(ctx, NULL); + _cmsAllocMPETypePluginChunk(ctx, NULL); + _cmsAllocTagPluginChunk(ctx, NULL); + _cmsAllocIntentsPluginChunk(ctx, NULL); + _cmsAllocOptimizationPluginChunk(ctx, NULL); + _cmsAllocTransformPluginChunk(ctx, NULL); + _cmsAllocMutexPluginChunk(ctx, NULL); + + // Setup the plug-ins + if (!cmsPluginTHR(ctx, Plugin)) { + + cmsDeleteContext(ctx); + return NULL; + } + + return (cmsContext) ctx; +} + +// Duplicates a context with all associated plug-ins. +// Caller may specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) +{ + int i; + struct _cmsContext_struct* ctx; + const struct _cmsContext_struct* src = _cmsGetContext(ContextID); + + void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr]; + + + ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened + + // Setup default memory allocators + memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + // Maintain the linked list + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + ctx ->Next = _cmsContextPoolHead; + _cmsContextPoolHead = ctx; + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + ctx ->chunks[UserPtr] = userData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + // Allocate all required chunks. + _cmsAllocLogErrorChunk(ctx, src); + _cmsAllocAlarmCodesChunk(ctx, src); + _cmsAllocAdaptationStateChunk(ctx, src); + _cmsAllocMemPluginChunk(ctx, src); + _cmsAllocInterpPluginChunk(ctx, src); + _cmsAllocCurvesPluginChunk(ctx, src); + _cmsAllocFormattersPluginChunk(ctx, src); + _cmsAllocTagTypePluginChunk(ctx, src); + _cmsAllocMPETypePluginChunk(ctx, src); + _cmsAllocTagPluginChunk(ctx, src); + _cmsAllocIntentsPluginChunk(ctx, src); + _cmsAllocOptimizationPluginChunk(ctx, src); + _cmsAllocTransformPluginChunk(ctx, src); + _cmsAllocMutexPluginChunk(ctx, src); + + // Make sure no one failed + for (i=Logger; i < MemoryClientMax; i++) { + + if (src ->chunks[i] == NULL) { + cmsDeleteContext((cmsContext) ctx); + return NULL; + } + } + + return (cmsContext) ctx; +} + + +// Frees any resources associated with the given context, +// and destroys the context placeholder. +// The ContextID can no longer be used in any THR operation. +void CMSEXPORT cmsDeleteContext(cmsContext ContextID) +{ + if (ContextID != NULL) { + + struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct fakeContext; + struct _cmsContext_struct* prev; + + memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr]; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Get rid of plugins + cmsUnregisterPluginsTHR(ContextID); + + // Since all memory is allocated in the private pool, all what we need to do is destroy the pool + if (ctx -> MemPool != NULL) + _cmsSubAllocDestroy(ctx ->MemPool); + ctx -> MemPool = NULL; + + // Maintain list + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + if (_cmsContextPoolHead == ctx) { + + _cmsContextPoolHead = ctx->Next; + } + else { + + // Search for previous + for (prev = _cmsContextPoolHead; + prev != NULL; + prev = prev ->Next) + { + if (prev -> Next == ctx) { + prev -> Next = ctx ->Next; + break; + } + } + } + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + // free the memory block itself + _cmsFree(&fakeContext, ctx); + } +} + +// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation +void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) +{ + return _cmsContextGetClientChunk(ContextID, UserPtr); +} + + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsps2.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsps2.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsps2.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsps2.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1647 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// PostScript ColorRenderingDictionary and ColorSpaceArray + + +#define MAXPSCOLS 60 // Columns on tables + +/* + Implementation + -------------- + + PostScript does use XYZ as its internal PCS. But since PostScript + interpolation tables are limited to 8 bits, I use Lab as a way to + improve the accuracy, favoring perceptual results. So, for the creation + of each CRD, CSA the profiles are converted to Lab via a device + link between profile -> Lab or Lab -> profile. The PS code necessary to + convert Lab <-> XYZ is also included. + + + + Color Space Arrays (CSA) + ================================================================================== + + In order to obtain precision, code chooses between three ways to implement + the device -> XYZ transform. These cases identifies monochrome profiles (often + implemented as a set of curves), matrix-shaper and Pipeline-based. + + Monochrome + ----------- + + This is implemented as /CIEBasedA CSA. The prelinearization curve is + placed into /DecodeA section, and matrix equals to D50. Since here is + no interpolation tables, I do the conversion directly to XYZ + + NOTE: CLUT-based monochrome profiles are NOT supported. So, cmsFLAGS_MATRIXINPUT + flag is forced on such profiles. + + [ /CIEBasedA + << + /DecodeA { transfer function } bind + /MatrixA [D50] + /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ] + /WhitePoint [D50] + /BlackPoint [BP] + /RenderingIntent (intent) + >> + ] + + On simpler profiles, the PCS is already XYZ, so no conversion is required. + + + Matrix-shaper based + ------------------- + + This is implemented both with /CIEBasedABC or /CIEBasedDEF depending on the + profile implementation. Since here there are no interpolation tables, I do + the conversion directly to XYZ + + + + [ /CIEBasedABC + << + /DecodeABC [ {transfer1} {transfer2} {transfer3} ] + /MatrixABC [Matrix] + /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ] + /DecodeLMN [ { / 2} dup dup ] + /WhitePoint [D50] + /BlackPoint [BP] + /RenderingIntent (intent) + >> + ] + + + CLUT based + ---------- + + Lab is used in such cases. + + [ /CIEBasedDEF + << + /DecodeDEF [ ] + /Table [ p p p [<...>]] + /RangeABC [ 0 1 0 1 0 1] + /DecodeABC[ ] + /RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ] + % -128/500 1+127/500 0 1 -127/200 1+128/200 + /MatrixABC [ 1 1 1 1 0 0 0 0 -1] + /WhitePoint [D50] + /BlackPoint [BP] + /RenderingIntent (intent) + ] + + + Color Rendering Dictionaries (CRD) + ================================== + These are always implemented as CLUT, and always are using Lab. Since CRD are expected to + be used as resources, the code adds the definition as well. + + << + /ColorRenderingType 1 + /WhitePoint [ D50 ] + /BlackPoint [BP] + /MatrixPQR [ Bradford ] + /RangePQR [-0.125 1.375 -0.125 1.375 -0.125 1.375 ] + /TransformPQR [ + {4 index 3 get div 2 index 3 get mul exch pop exch pop exch pop exch pop } bind + {4 index 4 get div 2 index 4 get mul exch pop exch pop exch pop exch pop } bind + {4 index 5 get div 2 index 5 get mul exch pop exch pop exch pop exch pop } bind + ] + /MatrixABC <...> + /EncodeABC <...> + /RangeABC <.. used for XYZ -> Lab> + /EncodeLMN + /RenderTable [ p p p [<...>]] + + /RenderingIntent (Perceptual) + >> + /Current exch /ColorRendering defineresource pop + + + The following stages are used to convert from XYZ to Lab + -------------------------------------------------------- + + Input is given at LMN stage on X, Y, Z + + Encode LMN gives us f(X/Xn), f(Y/Yn), f(Z/Zn) + + /EncodeLMN [ + + { 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind + { 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind + { 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind + + ] + + + MatrixABC is used to compute f(Y/Yn), f(X/Xn) - f(Y/Yn), f(Y/Yn) - f(Z/Zn) + + | 0 1 0| + | 1 -1 0| + | 0 1 -1| + + /MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ] + + EncodeABC finally gives Lab values. + + /EncodeABC [ + { 116 mul 16 sub 100 div } bind + { 500 mul 128 add 255 div } bind + { 200 mul 128 add 255 div } bind + ] + + The following stages are used to convert Lab to XYZ + ---------------------------------------------------- + + /RangeABC [ 0 1 0 1 0 1] + /DecodeABC [ { 100 mul 16 add 116 div } bind + { 255 mul 128 sub 500 div } bind + { 255 mul 128 sub 200 div } bind + ] + + /MatrixABC [ 1 1 1 1 0 0 0 0 -1] + /DecodeLMN [ + {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind + {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind + {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind + ] + + +*/ + +/* + + PostScript algorithms discussion. + ========================================================================================================= + + 1D interpolation algorithm + + + 1D interpolation (float) + ------------------------ + + val2 = Domain * Value; + + cell0 = (int) floor(val2); + cell1 = (int) ceil(val2); + + rest = val2 - cell0; + + y0 = LutTable[cell0] ; + y1 = LutTable[cell1] ; + + y = y0 + (y1 - y0) * rest; + + + + PostScript code Stack + ================================================ + + { % v + + [array] % v tab + dup % v tab tab + length 1 sub % v tab dom + + 3 -1 roll % tab dom v + + mul % tab val2 + dup % tab val2 val2 + dup % tab val2 val2 val2 + floor cvi % tab val2 val2 cell0 + exch % tab val2 cell0 val2 + ceiling cvi % tab val2 cell0 cell1 + + 3 index % tab val2 cell0 cell1 tab + exch % tab val2 cell0 tab cell1 + get % tab val2 cell0 y1 + + 4 -1 roll % val2 cell0 y1 tab + 3 -1 roll % val2 y1 tab cell0 + get % val2 y1 y0 + + dup % val2 y1 y0 y0 + 3 1 roll % val2 y0 y1 y0 + + sub % val2 y0 (y1-y0) + 3 -1 roll % y0 (y1-y0) val2 + dup % y0 (y1-y0) val2 val2 + floor cvi % y0 (y1-y0) val2 floor(val2) + sub % y0 (y1-y0) rest + mul % y0 t1 + add % y + 65535 div % result + + } bind + + +*/ + + +// This struct holds the memory block currently being write +typedef struct { + _cmsStageCLutData* Pipeline; + cmsIOHANDLER* m; + + int FirstComponent; + int SecondComponent; + + const char* PreMaj; + const char* PostMaj; + const char* PreMin; + const char* PostMin; + + int FixWhite; // Force mapping of pure white + + cmsColorSpaceSignature ColorSpace; // ColorSpace of profile + + +} cmsPsSamplerCargo; + +static int _cmsPSActualColumn = 0; + + +// Convert to byte +static +cmsUInt8Number Word2Byte(cmsUInt16Number w) +{ + return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5); +} + + +// Write a cooked byte +static +void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b) +{ + _cmsIOPrintf(m, "%02x", b); + _cmsPSActualColumn += 2; + + if (_cmsPSActualColumn > MAXPSCOLS) { + + _cmsIOPrintf(m, "\n"); + _cmsPSActualColumn = 0; + } +} + +// ----------------------------------------------------------------- PostScript generation + + +// Removes offending carriage returns + +static +char* RemoveCR(const char* txt) +{ + static char Buffer[2048]; + char* pt; + + strncpy(Buffer, txt, 2047); + Buffer[2047] = 0; + for (pt = Buffer; *pt; pt++) + if (*pt == '\n' || *pt == '\r') *pt = ' '; + + return Buffer; + +} + +static +void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile) +{ + time_t timer; + cmsMLU *Description, *Copyright; + char DescASCII[256], CopyrightASCII[256]; + + time(&timer); + + Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag); + Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag); + + DescASCII[0] = DescASCII[255] = 0; + CopyrightASCII[0] = CopyrightASCII[255] = 0; + + if (Description != NULL) cmsMLUgetASCII(Description, cmsNoLanguage, cmsNoCountry, DescASCII, 255); + if (Copyright != NULL) cmsMLUgetASCII(Copyright, cmsNoLanguage, cmsNoCountry, CopyrightASCII, 255); + + _cmsIOPrintf(m, "%%!PS-Adobe-3.0\n"); + _cmsIOPrintf(m, "%%\n"); + _cmsIOPrintf(m, "%% %s\n", Title); + _cmsIOPrintf(m, "%% Source: %s\n", RemoveCR(DescASCII)); + _cmsIOPrintf(m, "%% %s\n", RemoveCR(CopyrightASCII)); + _cmsIOPrintf(m, "%% Created: %s", ctime(&timer)); // ctime appends a \n!!! + _cmsIOPrintf(m, "%%\n"); + _cmsIOPrintf(m, "%%%%BeginResource\n"); + +} + + +// Emits White & Black point. White point is always D50, Black point is the device +// Black point adapted to D50. + +static +void EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint) +{ + + _cmsIOPrintf(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X, + BlackPoint -> Y, + BlackPoint -> Z); + + _cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X, + cmsD50_XYZ()->Y, + cmsD50_XYZ()->Z); +} + + +static +void EmitRangeCheck(cmsIOHANDLER* m) +{ + _cmsIOPrintf(m, "dup 0.0 lt { pop 0.0 } if " + "dup 1.0 gt { pop 1.0 } if "); + +} + +// Does write the intent + +static +void EmitIntent(cmsIOHANDLER* m, cmsUInt32Number RenderingIntent) +{ + const char *intent; + + switch (RenderingIntent) { + + case INTENT_PERCEPTUAL: intent = "Perceptual"; break; + case INTENT_RELATIVE_COLORIMETRIC: intent = "RelativeColorimetric"; break; + case INTENT_ABSOLUTE_COLORIMETRIC: intent = "AbsoluteColorimetric"; break; + case INTENT_SATURATION: intent = "Saturation"; break; + + default: intent = "Undefined"; break; + } + + _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent ); +} + +// +// Convert L* to Y +// +// Y = Yn*[ (L* + 16) / 116] ^ 3 if (L*) >= 6 / 29 +// = Yn*( L* / 116) / 7.787 if (L*) < 6 / 29 +// + +// Lab -> XYZ, see the discussion above + +static +void EmitLab2XYZ(cmsIOHANDLER* m) +{ + _cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n"); + _cmsIOPrintf(m, "/DecodeABC [\n"); + _cmsIOPrintf(m, "{100 mul 16 add 116 div } bind\n"); + _cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n"); + _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n"); + _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n"); + _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n"); + _cmsIOPrintf(m, "/DecodeLMN [\n"); + _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n"); + _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n"); + _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n"); + _cmsIOPrintf(m, "]\n"); +} + +static +void EmitSafeGuardBegin(cmsIOHANDLER* m, const char* name) +{ + _cmsIOPrintf(m, "%%LCMS2: Save previous definition of %s on the operand stack\n", name); + _cmsIOPrintf(m, "currentdict /%s known { /%s load } { null } ifelse\n", name, name); +} + +static +void EmitSafeGuardEnd(cmsIOHANDLER* m, const char* name, int depth) +{ + _cmsIOPrintf(m, "%%LCMS2: Restore previous definition of %s\n", name); + if (depth > 1) { + // cycle topmost items on the stack to bring the previous definition to the front + _cmsIOPrintf(m, "%d -1 roll ", depth); + } + _cmsIOPrintf(m, "dup null eq { pop currentdict /%s undef } { /%s exch def } ifelse\n", name, name); +} + +// Outputs a table of words. It does use 16 bits + +static +void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name) +{ + cmsUInt32Number i; + cmsFloat64Number gamma; + + if (Table == NULL) return; // Error + + if (Table ->nEntries <= 0) return; // Empty table + + // Suppress whole if identity + if (cmsIsToneCurveLinear(Table)) return; + + // Check if is really an exponential. If so, emit "exp" + gamma = cmsEstimateGamma(Table, 0.001); + if (gamma > 0) { + _cmsIOPrintf(m, "/%s { %g exp } bind def\n", name, gamma); + return; + } + + EmitSafeGuardBegin(m, "lcms2gammatable"); + _cmsIOPrintf(m, "/lcms2gammatable ["); + + for (i=0; i < Table->nEntries; i++) { + if (i % 10 == 0) + _cmsIOPrintf(m, "\n "); + _cmsIOPrintf(m, "%d ", Table->Table16[i]); + } + + _cmsIOPrintf(m, "] def\n"); + + + // Emit interpolation code + + // PostScript code Stack + // =============== ======================== + // v + _cmsIOPrintf(m, "/%s {\n ", name); + + // Bounds check + EmitRangeCheck(m); + + _cmsIOPrintf(m, "\n //lcms2gammatable "); // v tab + _cmsIOPrintf(m, "dup "); // v tab tab + _cmsIOPrintf(m, "length 1 sub "); // v tab dom + _cmsIOPrintf(m, "3 -1 roll "); // tab dom v + _cmsIOPrintf(m, "mul "); // tab val2 + _cmsIOPrintf(m, "dup "); // tab val2 val2 + _cmsIOPrintf(m, "dup "); // tab val2 val2 val2 + _cmsIOPrintf(m, "floor cvi "); // tab val2 val2 cell0 + _cmsIOPrintf(m, "exch "); // tab val2 cell0 val2 + _cmsIOPrintf(m, "ceiling cvi "); // tab val2 cell0 cell1 + _cmsIOPrintf(m, "3 index "); // tab val2 cell0 cell1 tab + _cmsIOPrintf(m, "exch "); // tab val2 cell0 tab cell1 + _cmsIOPrintf(m, "get\n "); // tab val2 cell0 y1 + _cmsIOPrintf(m, "4 -1 roll "); // val2 cell0 y1 tab + _cmsIOPrintf(m, "3 -1 roll "); // val2 y1 tab cell0 + _cmsIOPrintf(m, "get "); // val2 y1 y0 + _cmsIOPrintf(m, "dup "); // val2 y1 y0 y0 + _cmsIOPrintf(m, "3 1 roll "); // val2 y0 y1 y0 + _cmsIOPrintf(m, "sub "); // val2 y0 (y1-y0) + _cmsIOPrintf(m, "3 -1 roll "); // y0 (y1-y0) val2 + _cmsIOPrintf(m, "dup "); // y0 (y1-y0) val2 val2 + _cmsIOPrintf(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2) + _cmsIOPrintf(m, "sub "); // y0 (y1-y0) rest + _cmsIOPrintf(m, "mul "); // y0 t1 + _cmsIOPrintf(m, "add "); // y + _cmsIOPrintf(m, "65535 div\n"); // result + + _cmsIOPrintf(m, "} bind def\n"); + + EmitSafeGuardEnd(m, "lcms2gammatable", 1); +} + + +// Compare gamma table + +static +cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Number nG1, cmsUInt32Number nG2) +{ + if (nG1 != nG2) return FALSE; + return memcmp(g1, g2, nG1 * sizeof(cmsUInt16Number)) == 0; +} + + +// Does write a set of gamma curves + +static +void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const char* nameprefix) +{ + cmsUInt32Number i; + static char buffer[2048]; + + for( i=0; i < n; i++ ) + { + if (g[i] == NULL) return; // Error + + if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i-1]->nEntries, g[i]->nEntries)) { + + _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1); + } + else { + snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i); + buffer[sizeof(buffer)-1] = '\0'; + Emit1Gamma(m, g[i], buffer); + } + } + +} + + +// Following code dumps a LUT onto memory stream + + +// This is the sampler. Intended to work in SAMPLER_INSPECT mode, +// that is, the callback will be called for each knot with +// +// In[] The grid location coordinates, normalized to 0..ffff +// Out[] The Pipeline values, normalized to 0..ffff +// +// Returning a value other than 0 does terminate the sampling process +// +// Each row contains Pipeline values for all but first component. So, I +// detect row changing by keeping a copy of last value of first +// component. -1 is used to mark beginning of whole block. + +static +int OutputValueSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo) +{ + cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo; + cmsUInt32Number i; + + + if (sc -> FixWhite) { + + if (In[0] == 0xFFFF) { // Only in L* = 100, ab = [-8..8] + + if ((In[1] >= 0x7800 && In[1] <= 0x8800) && + (In[2] >= 0x7800 && In[2] <= 0x8800)) { + + cmsUInt16Number* Black; + cmsUInt16Number* White; + cmsUInt32Number nOutputs; + + if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs)) + return 0; + + for (i=0; i < nOutputs; i++) + Out[i] = White[i]; + } + + + } + } + + + // Hadle the parenthesis on rows + + if (In[0] != sc ->FirstComponent) { + + if (sc ->FirstComponent != -1) { + + _cmsIOPrintf(sc ->m, sc ->PostMin); + sc ->SecondComponent = -1; + _cmsIOPrintf(sc ->m, sc ->PostMaj); + } + + // Begin block + _cmsPSActualColumn = 0; + + _cmsIOPrintf(sc ->m, sc ->PreMaj); + sc ->FirstComponent = In[0]; + } + + + if (In[1] != sc ->SecondComponent) { + + if (sc ->SecondComponent != -1) { + + _cmsIOPrintf(sc ->m, sc ->PostMin); + } + + _cmsIOPrintf(sc ->m, sc ->PreMin); + sc ->SecondComponent = In[1]; + } + + // Dump table. + + for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) { + + cmsUInt16Number wWordOut = Out[i]; + cmsUInt8Number wByteOut; // Value as byte + + + // We always deal with Lab4 + + wByteOut = Word2Byte(wWordOut); + WriteByte(sc -> m, wByteOut); + } + + return 1; +} + +// Writes a Pipeline on memstream. Could be 8 or 16 bits based + +static +void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj, + const char* PostMaj, + const char* PreMin, + const char* PostMin, + int FixWhite, + cmsColorSpaceSignature ColorSpace) +{ + cmsUInt32Number i; + cmsPsSamplerCargo sc; + + sc.FirstComponent = -1; + sc.SecondComponent = -1; + sc.Pipeline = (_cmsStageCLutData *) mpe ->Data; + sc.m = m; + sc.PreMaj = PreMaj; + sc.PostMaj= PostMaj; + + sc.PreMin = PreMin; + sc.PostMin = PostMin; + sc.FixWhite = FixWhite; + sc.ColorSpace = ColorSpace; + + _cmsIOPrintf(m, "["); + + for (i=0; i < sc.Pipeline->Params->nInputs; i++) + _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); + + _cmsIOPrintf(m, " [\n"); + + cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT); + + _cmsIOPrintf(m, PostMin); + _cmsIOPrintf(m, PostMaj); + _cmsIOPrintf(m, "] "); + +} + + +// Dumps CIEBasedA Color Space Array + +static +int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint) +{ + + _cmsIOPrintf(m, "[ /CIEBasedA\n"); + _cmsIOPrintf(m, " <<\n"); + + EmitSafeGuardBegin(m, "lcms2gammaproc"); + Emit1Gamma(m, Curve, "lcms2gammaproc"); + + _cmsIOPrintf(m, "/DecodeA /lcms2gammaproc load\n"); + EmitSafeGuardEnd(m, "lcms2gammaproc", 3); + + _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n"); + _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); + + EmitWhiteBlackD50(m, BlackPoint); + EmitIntent(m, INTENT_PERCEPTUAL); + + _cmsIOPrintf(m, ">>\n"); + _cmsIOPrintf(m, "]\n"); + + return 1; +} + + +// Dumps CIEBasedABC Color Space Array + +static +int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint) +{ + int i; + + _cmsIOPrintf(m, "[ /CIEBasedABC\n"); + _cmsIOPrintf(m, "<<\n"); + + EmitSafeGuardBegin(m, "lcms2gammaproc0"); + EmitSafeGuardBegin(m, "lcms2gammaproc1"); + EmitSafeGuardBegin(m, "lcms2gammaproc2"); + EmitNGamma(m, 3, CurveSet, "lcms2gammaproc"); + _cmsIOPrintf(m, "/DecodeABC [\n"); + _cmsIOPrintf(m, " /lcms2gammaproc0 load\n"); + _cmsIOPrintf(m, " /lcms2gammaproc1 load\n"); + _cmsIOPrintf(m, " /lcms2gammaproc2 load\n"); + _cmsIOPrintf(m, "]\n"); + EmitSafeGuardEnd(m, "lcms2gammaproc2", 3); + EmitSafeGuardEnd(m, "lcms2gammaproc1", 3); + EmitSafeGuardEnd(m, "lcms2gammaproc0", 3); + + _cmsIOPrintf(m, "/MatrixABC [ " ); + + for( i=0; i < 3; i++ ) { + + _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0], + Matrix[i + 3*1], + Matrix[i + 3*2]); + } + + + _cmsIOPrintf(m, "]\n"); + + _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); + + EmitWhiteBlackD50(m, BlackPoint); + EmitIntent(m, INTENT_PERCEPTUAL); + + _cmsIOPrintf(m, ">>\n"); + _cmsIOPrintf(m, "]\n"); + + + return 1; +} + + +static +int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint) +{ + const char* PreMaj; + const char* PostMaj; + const char* PreMin, * PostMin; + cmsStage* mpe; + int i, numchans; + static char buffer[2048]; + + mpe = Pipeline->Elements; + + switch (cmsStageInputChannels(mpe)) { + case 3: + _cmsIOPrintf(m, "[ /CIEBasedDEF\n"); + PreMaj = "<"; + PostMaj = ">\n"; + PreMin = PostMin = ""; + break; + + case 4: + _cmsIOPrintf(m, "[ /CIEBasedDEFG\n"); + PreMaj = "["; + PostMaj = "]\n"; + PreMin = "<"; + PostMin = ">\n"; + break; + + default: + return 0; + + } + + _cmsIOPrintf(m, "<<\n"); + + if (cmsStageType(mpe) == cmsSigCurveSetElemType) { + + numchans = (int) cmsStageOutputChannels(mpe); + for (i = 0; i < numchans; ++i) { + snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i); + buffer[sizeof(buffer) - 1] = '\0'; + EmitSafeGuardBegin(m, buffer); + } + EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe), "lcms2gammaproc"); + _cmsIOPrintf(m, "/DecodeDEF [\n"); + for (i = 0; i < numchans; ++i) { + snprintf(buffer, sizeof(buffer), " /lcms2gammaproc%d load\n", i); + buffer[sizeof(buffer) - 1] = '\0'; + _cmsIOPrintf(m, buffer); + } + _cmsIOPrintf(m, "]\n"); + for (i = numchans - 1; i >= 0; --i) { + snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i); + buffer[sizeof(buffer) - 1] = '\0'; + EmitSafeGuardEnd(m, buffer, 3); + } + + mpe = mpe->Next; + } + + if (cmsStageType(mpe) == cmsSigCLutElemType) { + + _cmsIOPrintf(m, "/Table "); + WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature)0); + _cmsIOPrintf(m, "]\n"); + } + + EmitLab2XYZ(m); + EmitWhiteBlackD50(m, BlackPoint); + EmitIntent(m, Intent); + + _cmsIOPrintf(m, " >>\n"); + _cmsIOPrintf(m, "]\n"); + + return 1; +} + +// Generates a curve from a gray profile + +static +cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent) +{ + cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); + cmsHPROFILE hXYZ = cmsCreateXYZProfile(); + cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE); + int i; + + if (Out != NULL && xform != NULL) { + for (i=0; i < 256; i++) { + + cmsUInt8Number Gray = (cmsUInt8Number) i; + cmsCIEXYZ XYZ; + + cmsDoTransform(xform, &Gray, &XYZ, 1); + + Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0); + } + } + + if (xform) cmsDeleteTransform(xform); + if (hXYZ) cmsCloseProfile(hXYZ); + return Out; +} + + + +// Because PostScript has only 8 bits in /Table, we should use +// a more perceptually uniform space... I do choose Lab. + +static +int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) +{ + cmsHPROFILE hLab; + cmsHTRANSFORM xform; + cmsUInt32Number nChannels; + cmsUInt32Number InputFormat; + int rc; + cmsHPROFILE Profiles[2]; + cmsCIEXYZ BlackPointAdaptedToD50; + + // Does create a device-link based transform. + // The DeviceLink is next dumped as working CSA. + + InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); + nChannels = T_CHANNELS(InputFormat); + + + cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); + + // Adjust output to Lab4 + hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); + + Profiles[0] = hProfile; + Profiles[1] = hLab; + + xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0); + cmsCloseProfile(hLab); + + if (xform == NULL) { + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab"); + return 0; + } + + // Only 1, 3 and 4 channels are allowed + + switch (nChannels) { + + case 1: { + cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); + EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50); + cmsFreeToneCurve(Gray2Y); + } + break; + + case 3: + case 4: { + cmsUInt32Number OutFrm = TYPE_Lab_16; + cmsPipeline* DeviceLink; + _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; + + DeviceLink = cmsPipelineDup(v ->Lut); + if (DeviceLink == NULL) return 0; + + dwFlags |= cmsFLAGS_FORCE_CLUT; + _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); + + rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); + cmsPipelineFree(DeviceLink); + if (rc == 0) return 0; + } + break; + + default: + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels are supported for CSA. This profile has %d channels.", nChannels); + return 0; + } + + + cmsDeleteTransform(xform); + + return 1; +} + +static +cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe) +{ + _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + + return Data -> Double; +} + + +// Does create CSA based on matrix-shaper. Allowed types are gray and RGB based +static +int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper) +{ + cmsColorSpaceSignature ColorSpace; + int rc; + cmsCIEXYZ BlackPointAdaptedToD50; + + ColorSpace = cmsGetColorSpace(hProfile); + + cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0); + + if (ColorSpace == cmsSigGrayData) { + + cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper); + rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50); + + } + else + if (ColorSpace == cmsSigRgbData) { + + cmsMAT3 Mat; + int i, j; + + memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat)); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ; + + rc = EmitCIEBasedABC(m, (cmsFloat64Number *)&Mat, + _cmsStageGetPtrToCurveSet(Shaper), + &BlackPointAdaptedToD50); + } + else { + + cmsSignalError(m->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace."); + return 0; + } + + return rc; +} + + + +// Creates a PostScript color list from a named profile data. +// This is a HP extension, and it works in Lab instead of XYZ + +static +int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent) +{ + cmsHTRANSFORM xform; + cmsHPROFILE hLab; + cmsUInt32Number i, nColors; + char ColorName[cmsMAX_PATH]; + cmsNAMEDCOLORLIST* NamedColorList; + + hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); + xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0); + if (xform == NULL) return 0; + + NamedColorList = cmsGetNamedColorList(xform); + if (NamedColorList == NULL) return 0; + + _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA"); + _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); + _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); + + nColors = cmsNamedColorCount(NamedColorList); + + + for (i=0; i < nColors; i++) { + + cmsUInt16Number In[1]; + cmsCIELab Lab; + + In[0] = (cmsUInt16Number) i; + + if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) + continue; + + cmsDoTransform(xform, In, &Lab, 1); + _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b); + } + + + + _cmsIOPrintf(m, ">>\n"); + + cmsDeleteTransform(xform); + cmsCloseProfile(hLab); + return 1; +} + + +// Does create a Color Space Array on XYZ colorspace for PostScript usage +static +cmsUInt32Number GenerateCSA(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + cmsIOHANDLER* mem) +{ + cmsUInt32Number dwBytesUsed; + cmsPipeline* lut = NULL; + cmsStage* Matrix, *Shaper; + + + // Is a named color profile? + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + + if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error; + } + else { + + + // Any profile class are allowed (including devicelink), but + // output (PCS) colorspace must be XYZ or Lab + cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); + + if (ColorSpace != cmsSigXYZData && + ColorSpace != cmsSigLabData) { + + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space"); + goto Error; + } + + + // Read the lut with all necessary conversion stages + lut = _cmsReadInputLUT(hProfile, Intent); + if (lut == NULL) goto Error; + + + // Tone curves + matrix can be implemented without any LUT + if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) { + + if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error; + + } + else { + // We need a LUT for the rest + if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error; + } + } + + + // Done, keep memory usage + dwBytesUsed = mem ->UsedSpace; + + // Get rid of LUT + if (lut != NULL) cmsPipelineFree(lut); + + // Finally, return used byte count + return dwBytesUsed; + +Error: + if (lut != NULL) cmsPipelineFree(lut); + return 0; +} + +// ------------------------------------------------------ Color Rendering Dictionary (CRD) + + + +/* + + Black point compensation plus chromatic adaptation: + + Step 1 - Chromatic adaptation + ============================= + + WPout + X = ------- PQR + Wpin + + Step 2 - Black point compensation + ================================= + + (WPout - BPout)*X - WPout*(BPin - BPout) + out = --------------------------------------- + WPout - BPin + + + Algorithm discussion + ==================== + + TransformPQR(WPin, BPin, WPout, BPout, PQR) + + Wpin,etc= { Xws Yws Zws Pws Qws Rws } + + + Algorithm Stack 0...n + =========================================================== + PQR BPout WPout BPin WPin + 4 index 3 get WPin PQR BPout WPout BPin WPin + div (PQR/WPin) BPout WPout BPin WPin + 2 index 3 get WPout (PQR/WPin) BPout WPout BPin WPin + mult WPout*(PQR/WPin) BPout WPout BPin WPin + + 2 index 3 get WPout WPout*(PQR/WPin) BPout WPout BPin WPin + 2 index 3 get BPout WPout WPout*(PQR/WPin) BPout WPout BPin WPin + sub (WPout-BPout) WPout*(PQR/WPin) BPout WPout BPin WPin + mult (WPout-BPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + + 2 index 3 get WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + 4 index 3 get BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + 3 index 3 get BPout BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + + sub (BPin-BPout) WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + mult (BPin-BPout)*WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin + sub (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + + 3 index 3 get BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + 3 index 3 get WPout BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + exch + sub (WPout-BPin) (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin + div + + exch pop + exch pop + exch pop + exch pop + +*/ + + +static +void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute) +{ + + + if (lIsAbsolute) { + + // For absolute colorimetric intent, encode back to relative + // and generate a relative Pipeline + + // Relative encoding is obtained across XYZpcs*(D50/WhitePoint) + + cmsCIEXYZ White; + + _cmsReadMediaWhitePoint(&White, hProfile); + + _cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n"); + _cmsIOPrintf(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); + + _cmsIOPrintf(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n" + "/TransformPQR [\n" + "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n" + "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n" + "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n", + White.X, White.Y, White.Z); + return; + } + + + _cmsIOPrintf(m,"%% Bradford Cone Space\n" + "/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n"); + + _cmsIOPrintf(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n"); + + + // No BPC + + if (!DoBPC) { + + _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space\n" + "/TransformPQR [\n" + "{exch pop exch 3 get mul exch pop exch 3 get div} bind\n" + "{exch pop exch 4 get mul exch pop exch 4 get div} bind\n" + "{exch pop exch 5 get mul exch pop exch 5 get div} bind\n]\n"); + } else { + + // BPC + + _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n" + "/TransformPQR [\n"); + + _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul " + "2 index 3 get 2 index 3 get sub mul " + "2 index 3 get 4 index 3 get 3 index 3 get sub mul sub " + "3 index 3 get 3 index 3 get exch sub div " + "exch pop exch pop exch pop exch pop } bind\n"); + + _cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul " + "2 index 4 get 2 index 4 get sub mul " + "2 index 4 get 4 index 4 get 3 index 4 get sub mul sub " + "3 index 4 get 3 index 4 get exch sub div " + "exch pop exch pop exch pop exch pop } bind\n"); + + _cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul " + "2 index 5 get 2 index 5 get sub mul " + "2 index 5 get 4 index 5 get 3 index 5 get sub mul sub " + "3 index 5 get 3 index 5 get exch sub div " + "exch pop exch pop exch pop exch pop } bind\n]\n"); + + } +} + + +static +void EmitXYZ2Lab(cmsIOHANDLER* m) +{ + _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n"); + _cmsIOPrintf(m, "/EncodeLMN [\n"); + _cmsIOPrintf(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); + _cmsIOPrintf(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); + _cmsIOPrintf(m, "{ 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n"); + _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n"); + _cmsIOPrintf(m, "/EncodeABC [\n"); + + + _cmsIOPrintf(m, "{ 116 mul 16 sub 100 div } bind\n"); + _cmsIOPrintf(m, "{ 500 mul 128 add 256 div } bind\n"); + _cmsIOPrintf(m, "{ 200 mul 128 add 256 div } bind\n"); + + + _cmsIOPrintf(m, "]\n"); + + +} + +// Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces +// I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted +// space on 3D CLUT, but since space seems not to be a problem here, 33 points +// would give a reasonable accuracy. Note also that CRD tables must operate in +// 8 bits. + +static +int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) +{ + cmsHPROFILE hLab; + cmsHTRANSFORM xform; + cmsUInt32Number i, nChannels; + cmsUInt32Number OutputFormat; + _cmsTRANSFORM* v; + cmsPipeline* DeviceLink; + cmsHPROFILE Profiles[3]; + cmsCIEXYZ BlackPointAdaptedToD50; + cmsBool lDoBPC = (cmsBool) (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); + cmsBool lFixWhite = (cmsBool) !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP); + cmsUInt32Number InFrm = TYPE_Lab_16; + cmsUInt32Number RelativeEncodingIntent; + cmsColorSpaceSignature ColorSpace; + + + hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); + if (hLab == NULL) return 0; + + OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); + nChannels = T_CHANNELS(OutputFormat); + + ColorSpace = cmsGetColorSpace(hProfile); + + // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision. + + RelativeEncodingIntent = Intent; + if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) + RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; + + + // Use V4 Lab always + Profiles[0] = hLab; + Profiles[1] = hProfile; + + xform = cmsCreateMultiprofileTransformTHR(m ->ContextID, + Profiles, 2, TYPE_Lab_DBL, + OutputFormat, RelativeEncodingIntent, 0); + cmsCloseProfile(hLab); + + if (xform == NULL) { + + cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); + return 0; + } + + // Get a copy of the internal devicelink + v = (_cmsTRANSFORM*) xform; + DeviceLink = cmsPipelineDup(v ->Lut); + if (DeviceLink == NULL) return 0; + + + // We need a CLUT + dwFlags |= cmsFLAGS_FORCE_CLUT; + _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); + + _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "/ColorRenderingType 1\n"); + + + cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); + + // Emit headers, etc. + EmitWhiteBlackD50(m, &BlackPointAdaptedToD50); + EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); + EmitXYZ2Lab(m); + + + // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab + // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127, + // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to + // zero. This would sacrifice a bit of highlights, but failure to do so would cause + // scum dot. Ouch. + + if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) + lFixWhite = FALSE; + + _cmsIOPrintf(m, "/RenderTable "); + + + WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace); + + _cmsIOPrintf(m, " %d {} bind ", nChannels); + + for (i=1; i < nChannels; i++) + _cmsIOPrintf(m, "dup "); + + _cmsIOPrintf(m, "]\n"); + + + EmitIntent(m, Intent); + + _cmsIOPrintf(m, ">>\n"); + + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + + _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n"); + } + + cmsPipelineFree(DeviceLink); + cmsDeleteTransform(xform); + + return 1; +} + + +// Builds a ASCII string containing colorant list in 0..1.0 range +static +void BuildColorantList(char *Colorant, cmsUInt32Number nColorant, cmsUInt16Number Out[]) +{ + char Buff[32]; + cmsUInt32Number j; + + Colorant[0] = 0; + if (nColorant > cmsMAXCHANNELS) + nColorant = cmsMAXCHANNELS; + + for (j = 0; j < nColorant; j++) { + + snprintf(Buff, 31, "%.3f", Out[j] / 65535.0); + Buff[31] = 0; + strcat(Colorant, Buff); + if (j < nColorant - 1) + strcat(Colorant, " "); + + } +} + + +// Creates a PostScript color list from a named profile data. +// This is a HP extension. + +static +int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent, cmsUInt32Number dwFlags) +{ + cmsHTRANSFORM xform; + cmsUInt32Number i, nColors, nColorant; + cmsUInt32Number OutputFormat; + char ColorName[cmsMAX_PATH]; + char Colorant[512]; + cmsNAMEDCOLORLIST* NamedColorList; + + + OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE); + nColorant = T_CHANNELS(OutputFormat); + + + xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags); + if (xform == NULL) return 0; + + + NamedColorList = cmsGetNamedColorList(xform); + if (NamedColorList == NULL) return 0; + + _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile"); + _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); + _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); + + nColors = cmsNamedColorCount(NamedColorList); + + for (i=0; i < nColors; i++) { + + cmsUInt16Number In[1]; + cmsUInt16Number Out[cmsMAXCHANNELS]; + + In[0] = (cmsUInt16Number) i; + + if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) + continue; + + cmsDoTransform(xform, In, Out, 1); + BuildColorantList(Colorant, nColorant, Out); + _cmsIOPrintf(m, " (%s) [ %s ]\n", ColorName, Colorant); + } + + _cmsIOPrintf(m, " >>"); + + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + + _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n"); + } + + cmsDeleteTransform(xform); + return 1; +} + + + +// This one does create a Color Rendering Dictionary. +// CRD are always LUT-Based, no matter if profile is +// implemented as matrix-shaper. + +static +cmsUInt32Number GenerateCRD(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, cmsUInt32Number dwFlags, + cmsIOHANDLER* mem) +{ + cmsUInt32Number dwBytesUsed; + + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + + EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile); + } + + + // Is a named color profile? + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + + if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) { + return 0; + } + } + else { + + // CRD are always implemented as LUT + + if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) { + return 0; + } + } + + if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { + + _cmsIOPrintf(mem, "%%%%EndResource\n"); + _cmsIOPrintf(mem, "\n%% CRD End\n"); + } + + // Done, keep memory usage + dwBytesUsed = mem ->UsedSpace; + + // Finally, return used byte count + return dwBytesUsed; + + cmsUNUSED_PARAMETER(ContextID); +} + + + + +cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, + cmsPSResourceType Type, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + cmsIOHANDLER* io) +{ + cmsUInt32Number rc; + + + switch (Type) { + + case cmsPS_RESOURCE_CSA: + rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io); + break; + + default: + case cmsPS_RESOURCE_CRD: + rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io); + break; + } + + return rc; +} + + + +cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, cmsUInt32Number dwFlags, + void* Buffer, cmsUInt32Number dwBufferLen) +{ + cmsIOHANDLER* mem; + cmsUInt32Number dwBytesUsed; + + // Set up the serialization engine + if (Buffer == NULL) + mem = cmsOpenIOhandlerFromNULL(ContextID); + else + mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w"); + + if (!mem) return 0; + + dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem); + + // Get rid of memory stream + cmsCloseIOhandler(mem); + + return dwBytesUsed; +} + + + +// Does create a Color Space Array on XYZ colorspace for PostScript usage +cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + void* Buffer, + cmsUInt32Number dwBufferLen) +{ + cmsIOHANDLER* mem; + cmsUInt32Number dwBytesUsed; + + if (Buffer == NULL) + mem = cmsOpenIOhandlerFromNULL(ContextID); + else + mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w"); + + if (!mem) return 0; + + dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem); + + // Get rid of memory stream + cmsCloseIOhandler(mem); + + return dwBytesUsed; + +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmssamp.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmssamp.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmssamp.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmssamp.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,576 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +#define cmsmin(a, b) (((a) < (b)) ? (a) : (b)) +#define cmsmax(a, b) (((a) > (b)) ? (a) : (b)) + +// This file contains routines for resampling and LUT optimization, black point detection +// and black preservation. + +// Black point detection ------------------------------------------------------------------------- + + +// PCS -> PCS round trip transform, always uses relative intent on the device -> pcs +static +cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent) +{ + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsHPROFILE hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); + cmsHTRANSFORM xform; + cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE }; + cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 }; + cmsHPROFILE hProfiles[4]; + cmsUInt32Number Intents[4]; + + hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab; + Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC; + + xform = cmsCreateExtendedTransform(ContextID, 4, hProfiles, BPC, Intents, + States, NULL, 0, TYPE_Lab_DBL, TYPE_Lab_DBL, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + + cmsCloseProfile(hLab); + return xform; +} + +// Use darker colorants to obtain black point. This works in the relative colorimetric intent and +// assumes more ink results in darker colors. No ink limit is assumed. +static +cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, + cmsUInt32Number Intent, + cmsCIEXYZ* BlackPoint, + cmsUInt32Number dwFlags) +{ + cmsUInt16Number *Black; + cmsHTRANSFORM xform; + cmsColorSpaceSignature Space; + cmsUInt32Number nChannels; + cmsUInt32Number dwFormat; + cmsHPROFILE hLab; + cmsCIELab Lab; + cmsCIEXYZ BlackXYZ; + cmsContext ContextID = cmsGetProfileContextID(hInput); + + // If the profile does not support input direction, assume Black point 0 + if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) { + + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Create a formatter which has n channels and no floating point + dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2, FALSE); + + // Try to get black by using black colorant + Space = cmsGetColorSpace(hInput); + + // This function returns darker colorant in 16 bits for several spaces + if (!_cmsEndPointsBySpace(Space, NULL, &Black, &nChannels)) { + + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + if (nChannels != T_CHANNELS(dwFormat)) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Lab will be used as the output space, but lab2 will avoid recursion + hLab = cmsCreateLab2ProfileTHR(ContextID, NULL); + if (hLab == NULL) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Create the transform + xform = cmsCreateTransformTHR(ContextID, hInput, dwFormat, + hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); + cmsCloseProfile(hLab); + + if (xform == NULL) { + + // Something went wrong. Get rid of open resources and return zero as black + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Convert black to Lab + cmsDoTransform(xform, Black, &Lab, 1); + + // Force it to be neutral, clip to max. L* of 50 + Lab.a = Lab.b = 0; + if (Lab.L > 50) Lab.L = 50; + + // Free the resources + cmsDeleteTransform(xform); + + // Convert from Lab (which is now clipped) to XYZ. + cmsLab2XYZ(NULL, &BlackXYZ, &Lab); + + if (BlackPoint != NULL) + *BlackPoint = BlackXYZ; + + return TRUE; + + cmsUNUSED_PARAMETER(dwFlags); +} + +// Get a black point of output CMYK profile, discounting any ink-limiting embedded +// in the profile. For doing that, we use perceptual intent in input direction: +// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab +static +cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile) +{ + cmsHTRANSFORM hRoundTrip; + cmsCIELab LabIn, LabOut; + cmsCIEXYZ BlackXYZ; + + // Is the intent supported by the profile? + if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) { + + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return TRUE; + } + + hRoundTrip = CreateRoundtripXForm(hProfile, INTENT_PERCEPTUAL); + if (hRoundTrip == NULL) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + LabIn.L = LabIn.a = LabIn.b = 0; + cmsDoTransform(hRoundTrip, &LabIn, &LabOut, 1); + + // Clip Lab to reasonable limits + if (LabOut.L > 50) LabOut.L = 50; + LabOut.a = LabOut.b = 0; + + cmsDeleteTransform(hRoundTrip); + + // Convert it to XYZ + cmsLab2XYZ(NULL, &BlackXYZ, &LabOut); + + if (BlackPoint != NULL) + *BlackPoint = BlackXYZ; + + return TRUE; +} + +// This function shouldn't exist at all -- there is such quantity of broken +// profiles on black point tag, that we must somehow fix chromaticity to +// avoid huge tint when doing Black point compensation. This function does +// just that. There is a special flag for using black point tag, but turned +// off by default because it is bogus on most profiles. The detection algorithm +// involves to turn BP to neutral and to use only L component. +cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) +{ + cmsProfileClassSignature devClass; + + // Make sure the device class is adequate + devClass = cmsGetDeviceClass(hProfile); + if (devClass == cmsSigLinkClass || + devClass == cmsSigAbstractClass || + devClass == cmsSigNamedColorClass) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Make sure intent is adequate + if (Intent != INTENT_PERCEPTUAL && + Intent != INTENT_RELATIVE_COLORIMETRIC && + Intent != INTENT_SATURATION) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // v4 + perceptual & saturation intents does have its own black point, and it is + // well specified enough to use it. Black point tag is deprecated in V4. + if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && + (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { + + // Matrix shaper share MRC & perceptual intents + if (cmsIsMatrixShaper(hProfile)) + return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0); + + // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents + BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; + BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y; + BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z; + + return TRUE; + } + + +#ifdef CMS_USE_PROFILE_BLACK_POINT_TAG + + // v2, v4 rel/abs colorimetric + if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) && + Intent == INTENT_RELATIVE_COLORIMETRIC) { + + cmsCIEXYZ *BlackPtr, BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite; + cmsCIELab Lab; + + // If black point is specified, then use it, + + BlackPtr = cmsReadTag(hProfile, cmsSigMediaBlackPointTag); + if (BlackPtr != NULL) { + + BlackXYZ = *BlackPtr; + _cmsReadMediaWhitePoint(&MediaWhite, hProfile); + + // Black point is absolute XYZ, so adapt to D50 to get PCS value + cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ); + + // Force a=b=0 to get rid of any chroma + cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint); + Lab.a = Lab.b = 0; + if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50 + cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab); + + if (BlackPoint != NULL) + *BlackPoint = TrustedBlackPoint; + + return TRUE; + } + } +#endif + + // That is about v2 profiles. + + // If output profile, discount ink-limiting and that's all + if (Intent == INTENT_RELATIVE_COLORIMETRIC && + (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) && + (cmsGetColorSpace(hProfile) == cmsSigCmykData)) + return BlackPointUsingPerceptualBlack(BlackPoint, hProfile); + + // Nope, compute BP using current intent. + return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags); +} + + + +// --------------------------------------------------------------------------------------------------------- + +// Least Squares Fit of a Quadratic Curve to Data +// http://www.personal.psu.edu/jhm/f90/lectures/lsq2.html + +static +cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[], cmsFloat64Number y[]) +{ + double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0; + double sum_y = 0, sum_yx = 0, sum_yx2 = 0; + double d, a, b, c; + int i; + cmsMAT3 m; + cmsVEC3 v, res; + + if (n < 4) return 0; + + for (i=0; i < n; i++) { + + double xn = x[i]; + double yn = y[i]; + + sum_x += xn; + sum_x2 += xn*xn; + sum_x3 += xn*xn*xn; + sum_x4 += xn*xn*xn*xn; + + sum_y += yn; + sum_yx += yn*xn; + sum_yx2 += yn*xn*xn; + } + + _cmsVEC3init(&m.v[0], n, sum_x, sum_x2); + _cmsVEC3init(&m.v[1], sum_x, sum_x2, sum_x3); + _cmsVEC3init(&m.v[2], sum_x2, sum_x3, sum_x4); + + _cmsVEC3init(&v, sum_y, sum_yx, sum_yx2); + + if (!_cmsMAT3solve(&res, &m, &v)) return 0; + + + a = res.n[2]; + b = res.n[1]; + c = res.n[0]; + + if (fabs(a) < 1.0E-10) { + + return cmsmin(0, cmsmax(50, -c/b )); + } + else { + + d = b*b - 4.0 * a * c; + if (d <= 0) { + return 0; + } + else { + + double rt = (-b + sqrt(d)) / (2.0 * a); + + return cmsmax(0, cmsmin(50, rt)); + } + } + +} + + + +// Calculates the black point of a destination profile. +// This algorithm comes from the Adobe paper disclosing its black point compensation method. +cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) +{ + cmsColorSpaceSignature ColorSpace; + cmsHTRANSFORM hRoundTrip = NULL; + cmsCIELab InitialLab, destLab, Lab; + cmsFloat64Number inRamp[256], outRamp[256]; + cmsFloat64Number MinL, MaxL; + cmsBool NearlyStraightMidrange = TRUE; + cmsFloat64Number yRamp[256]; + cmsFloat64Number x[256], y[256]; + cmsFloat64Number lo, hi; + int n, l; + cmsProfileClassSignature devClass; + + // Make sure the device class is adequate + devClass = cmsGetDeviceClass(hProfile); + if (devClass == cmsSigLinkClass || + devClass == cmsSigAbstractClass || + devClass == cmsSigNamedColorClass) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + // Make sure intent is adequate + if (Intent != INTENT_PERCEPTUAL && + Intent != INTENT_RELATIVE_COLORIMETRIC && + Intent != INTENT_SATURATION) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + + // v4 + perceptual & saturation intents does have its own black point, and it is + // well specified enough to use it. Black point tag is deprecated in V4. + if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && + (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { + + // Matrix shaper share MRC & perceptual intents + if (cmsIsMatrixShaper(hProfile)) + return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0); + + // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents + BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; + BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y; + BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z; + return TRUE; + } + + + // Check if the profile is lut based and gray, rgb or cmyk (7.2 in Adobe's document) + ColorSpace = cmsGetColorSpace(hProfile); + if (!cmsIsCLUT(hProfile, Intent, LCMS_USED_AS_OUTPUT ) || + (ColorSpace != cmsSigGrayData && + ColorSpace != cmsSigRgbData && + ColorSpace != cmsSigCmykData)) { + + // In this case, handle as input case + return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags); + } + + // It is one of the valid cases!, use Adobe algorithm + + + // Set a first guess, that should work on good profiles. + if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + + cmsCIEXYZ IniXYZ; + + // calculate initial Lab as source black point + if (!cmsDetectBlackPoint(&IniXYZ, hProfile, Intent, dwFlags)) { + return FALSE; + } + + // convert the XYZ to lab + cmsXYZ2Lab(NULL, &InitialLab, &IniXYZ); + + } else { + + // set the initial Lab to zero, that should be the black point for perceptual and saturation + InitialLab.L = 0; + InitialLab.a = 0; + InitialLab.b = 0; + } + + + // Step 2 + // ====== + + // Create a roundtrip. Define a Transform BT for all x in L*a*b* + hRoundTrip = CreateRoundtripXForm(hProfile, Intent); + if (hRoundTrip == NULL) return FALSE; + + // Compute ramps + + for (l=0; l < 256; l++) { + + Lab.L = (cmsFloat64Number) (l * 100.0) / 255.0; + Lab.a = cmsmin(50, cmsmax(-50, InitialLab.a)); + Lab.b = cmsmin(50, cmsmax(-50, InitialLab.b)); + + cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); + + inRamp[l] = Lab.L; + outRamp[l] = destLab.L; + } + + // Make monotonic + for (l = 254; l > 0; --l) { + outRamp[l] = cmsmin(outRamp[l], outRamp[l+1]); + } + + // Check + if (! (outRamp[0] < outRamp[255])) { + + cmsDeleteTransform(hRoundTrip); + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + + // Test for mid range straight (only on relative colorimetric) + NearlyStraightMidrange = TRUE; + MinL = outRamp[0]; MaxL = outRamp[255]; + if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + + for (l=0; l < 256; l++) { + + if (! ((inRamp[l] <= MinL + 0.2 * (MaxL - MinL) ) || + (fabs(inRamp[l] - outRamp[l]) < 4.0 ))) + NearlyStraightMidrange = FALSE; + } + + // If the mid range is straight (as determined above) then the + // DestinationBlackPoint shall be the same as initialLab. + // Otherwise, the DestinationBlackPoint shall be determined + // using curve fitting. + if (NearlyStraightMidrange) { + + cmsLab2XYZ(NULL, BlackPoint, &InitialLab); + cmsDeleteTransform(hRoundTrip); + return TRUE; + } + } + + + // curve fitting: The round-trip curve normally looks like a nearly constant section at the black point, + // with a corner and a nearly straight line to the white point. + for (l=0; l < 256; l++) { + + yRamp[l] = (outRamp[l] - MinL) / (MaxL - MinL); + } + + // find the black point using the least squares error quadratic curve fitting + if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + lo = 0.1; + hi = 0.5; + } + else { + + // Perceptual and saturation + lo = 0.03; + hi = 0.25; + } + + // Capture shadow points for the fitting. + n = 0; + for (l=0; l < 256; l++) { + + cmsFloat64Number ff = yRamp[l]; + + if (ff >= lo && ff < hi) { + x[n] = inRamp[l]; + y[n] = yRamp[l]; + n++; + } + } + + + // No suitable points + if (n < 3 ) { + cmsDeleteTransform(hRoundTrip); + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } + + + // fit and get the vertex of quadratic curve + Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y); + + if (Lab.L < 0.0) { // clip to zero L* if the vertex is negative + Lab.L = 0; + } + + Lab.a = InitialLab.a; + Lab.b = InitialLab.b; + + cmsLab2XYZ(NULL, BlackPoint, &Lab); + + cmsDeleteTransform(hRoundTrip); + return TRUE; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmssm.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmssm.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmssm.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmssm.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,765 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// ------------------------------------------------------------------------ + +// Gamut boundary description by using Jan Morovic's Segment maxima method +// Many thanks to Jan for allowing me to use his algorithm. + +// r = C* +// alpha = Hab +// theta = L* + +#define SECTORS 16 // number of divisions in alpha and theta + +// Spherical coordinates +typedef struct { + + cmsFloat64Number r; + cmsFloat64Number alpha; + cmsFloat64Number theta; + +} cmsSpherical; + +typedef enum { + GP_EMPTY, + GP_SPECIFIED, + GP_MODELED + + } GDBPointType; + + +typedef struct { + + GDBPointType Type; + cmsSpherical p; // Keep also alpha & theta of maximum + +} cmsGDBPoint; + + +typedef struct { + + cmsContext ContextID; + cmsGDBPoint Gamut[SECTORS][SECTORS]; + +} cmsGDB; + + +// A line using the parametric form +// P = a + t*u +typedef struct { + + cmsVEC3 a; + cmsVEC3 u; + +} cmsLine; + + +// A plane using the parametric form +// Q = b + r*v + s*w +typedef struct { + + cmsVEC3 b; + cmsVEC3 v; + cmsVEC3 w; + +} cmsPlane; + + + +// -------------------------------------------------------------------------------------------- + +// ATAN2() which always returns degree positive numbers + +static +cmsFloat64Number _cmsAtan2(cmsFloat64Number y, cmsFloat64Number x) +{ + cmsFloat64Number a; + + // Deal with undefined case + if (x == 0.0 && y == 0.0) return 0; + + a = (atan2(y, x) * 180.0) / M_PI; + + while (a < 0) { + a += 360; + } + + return a; +} + +// Convert to spherical coordinates +static +void ToSpherical(cmsSpherical* sp, const cmsVEC3* v) +{ + + cmsFloat64Number L, a, b; + + L = v ->n[VX]; + a = v ->n[VY]; + b = v ->n[VZ]; + + sp ->r = sqrt( L*L + a*a + b*b ); + + if (sp ->r == 0) { + sp ->alpha = sp ->theta = 0; + return; + } + + sp ->alpha = _cmsAtan2(a, b); + sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L); +} + + +// Convert to cartesian from spherical +static +void ToCartesian(cmsVEC3* v, const cmsSpherical* sp) +{ + cmsFloat64Number sin_alpha; + cmsFloat64Number cos_alpha; + cmsFloat64Number sin_theta; + cmsFloat64Number cos_theta; + cmsFloat64Number L, a, b; + + sin_alpha = sin((M_PI * sp ->alpha) / 180.0); + cos_alpha = cos((M_PI * sp ->alpha) / 180.0); + sin_theta = sin((M_PI * sp ->theta) / 180.0); + cos_theta = cos((M_PI * sp ->theta) / 180.0); + + a = sp ->r * sin_theta * sin_alpha; + b = sp ->r * sin_theta * cos_alpha; + L = sp ->r * cos_theta; + + v ->n[VX] = L; + v ->n[VY] = a; + v ->n[VZ] = b; +} + + +// Quantize sector of a spherical coordinate. Saturate 360, 180 to last sector +// The limits are the centers of each sector, so +static +void QuantizeToSector(const cmsSpherical* sp, int* alpha, int* theta) +{ + *alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) ); + *theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) ); + + if (*alpha >= SECTORS) + *alpha = SECTORS-1; + if (*theta >= SECTORS) + *theta = SECTORS-1; +} + + +// Line determined by 2 points +static +void LineOf2Points(cmsLine* line, cmsVEC3* a, cmsVEC3* b) +{ + + _cmsVEC3init(&line ->a, a ->n[VX], a ->n[VY], a ->n[VZ]); + _cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX], + b ->n[VY] - a ->n[VY], + b ->n[VZ] - a ->n[VZ]); +} + + +// Evaluate parametric line +static +void GetPointOfLine(cmsVEC3* p, const cmsLine* line, cmsFloat64Number t) +{ + p ->n[VX] = line ->a.n[VX] + t * line->u.n[VX]; + p ->n[VY] = line ->a.n[VY] + t * line->u.n[VY]; + p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ]; +} + + + +/* + Closest point in sector line1 to sector line2 (both are defined as 0 <=t <= 1) + http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm + + Copyright 2001, softSurfer (www.softsurfer.com) + This code may be freely used and modified for any purpose + providing that this copyright notice is included with it. + SoftSurfer makes no warranty for this code, and cannot be held + liable for any real or imagined damage resulting from its use. + Users of this code must verify correctness for their application. + +*/ + +static +cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2) +{ + cmsFloat64Number a, b, c, d, e, D; + cmsFloat64Number sc, sN, sD; + //cmsFloat64Number tc; // left for future use + cmsFloat64Number tN, tD; + cmsVEC3 w0; + + _cmsVEC3minus(&w0, &line1 ->a, &line2 ->a); + + a = _cmsVEC3dot(&line1 ->u, &line1 ->u); + b = _cmsVEC3dot(&line1 ->u, &line2 ->u); + c = _cmsVEC3dot(&line2 ->u, &line2 ->u); + d = _cmsVEC3dot(&line1 ->u, &w0); + e = _cmsVEC3dot(&line2 ->u, &w0); + + D = a*c - b * b; // Denominator + sD = tD = D; // default sD = D >= 0 + + if (D < MATRIX_DET_TOLERANCE) { // the lines are almost parallel + + sN = 0.0; // force using point P0 on segment S1 + sD = 1.0; // to prevent possible division by 0.0 later + tN = e; + tD = c; + } + else { // get the closest points on the infinite lines + + sN = (b*e - c*d); + tN = (a*e - b*d); + + if (sN < 0.0) { // sc < 0 => the s=0 edge is visible + + sN = 0.0; + tN = e; + tD = c; + } + else if (sN > sD) { // sc > 1 => the s=1 edge is visible + sN = sD; + tN = e + b; + tD = c; + } + } + + if (tN < 0.0) { // tc < 0 => the t=0 edge is visible + + tN = 0.0; + // recompute sc for this edge + if (-d < 0.0) + sN = 0.0; + else if (-d > a) + sN = sD; + else { + sN = -d; + sD = a; + } + } + else if (tN > tD) { // tc > 1 => the t=1 edge is visible + + tN = tD; + + // recompute sc for this edge + if ((-d + b) < 0.0) + sN = 0; + else if ((-d + b) > a) + sN = sD; + else { + sN = (-d + b); + sD = a; + } + } + // finally do the division to get sc and tc + sc = (fabs(sN) < MATRIX_DET_TOLERANCE ? 0.0 : sN / sD); + //tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD); // left for future use. + + GetPointOfLine(r, line1, sc); + return TRUE; +} + + + +// ------------------------------------------------------------------ Wrapper + + +// Allocate & free structure +cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID) +{ + cmsGDB* gbd = (cmsGDB*) _cmsMallocZero(ContextID, sizeof(cmsGDB)); + if (gbd == NULL) return NULL; + + gbd -> ContextID = ContextID; + + return (cmsHANDLE) gbd; +} + + +void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD) +{ + cmsGDB* gbd = (cmsGDB*) hGBD; + if (hGBD != NULL) + _cmsFree(gbd->ContextID, (void*) gbd); +} + + +// Auxiliary to retrieve a pointer to the segmentr containing the Lab value +static +cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp) +{ + cmsVEC3 v; + int alpha, theta; + + // Housekeeping + _cmsAssert(gbd != NULL); + _cmsAssert(Lab != NULL); + _cmsAssert(sp != NULL); + + // Center L* by subtracting half of its domain, that's 50 + _cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b); + + // Convert to spherical coordinates + ToSpherical(sp, &v); + + if (sp ->r < 0 || sp ->alpha < 0 || sp->theta < 0) { + cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, "spherical value out of range"); + return NULL; + } + + // On which sector it falls? + QuantizeToSector(sp, &alpha, &theta); + + if (alpha < 0 || theta < 0 || alpha >= SECTORS || theta >= SECTORS) { + cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, " quadrant out of range"); + return NULL; + } + + // Get pointer to the sector + return &gbd ->Gamut[theta][alpha]; +} + +// Add a point to gamut descriptor. Point to add is in Lab color space. +// GBD is centered on a=b=0 and L*=50 +cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) +{ + cmsGDB* gbd = (cmsGDB*) hGBD; + cmsGDBPoint* ptr; + cmsSpherical sp; + + + // Get pointer to the sector + ptr = GetPoint(gbd, Lab, &sp); + if (ptr == NULL) return FALSE; + + // If no samples at this sector, add it + if (ptr ->Type == GP_EMPTY) { + + ptr -> Type = GP_SPECIFIED; + ptr -> p = sp; + } + else { + + + // Substitute only if radius is greater + if (sp.r > ptr -> p.r) { + + ptr -> Type = GP_SPECIFIED; + ptr -> p = sp; + } + } + + return TRUE; +} + +// Check if a given point falls inside gamut +cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab) +{ + cmsGDB* gbd = (cmsGDB*) hGBD; + cmsGDBPoint* ptr; + cmsSpherical sp; + + // Get pointer to the sector + ptr = GetPoint(gbd, Lab, &sp); + if (ptr == NULL) return FALSE; + + // If no samples at this sector, return no data + if (ptr ->Type == GP_EMPTY) return FALSE; + + // In gamut only if radius is greater + + return (sp.r <= ptr -> p.r); +} + +// ----------------------------------------------------------------------------------------------------------------------- + +// Find near sectors. The list of sectors found is returned on Close[]. +// The function returns the number of sectors as well. + +// 24 9 10 11 12 +// 23 8 1 2 13 +// 22 7 * 3 14 +// 21 6 5 4 15 +// 20 19 18 17 16 +// +// Those are the relative movements +// {-2,-2}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, +// {-2,-1}, {-1, -1}, {0, -1}, {+1, -1}, {+2, -1}, +// {-2, 0}, {-1, 0}, {0, 0}, {+1, 0}, {+2, 0}, +// {-2,+1}, {-1, +1}, {0, +1}, {+1, +1}, {+2, +1}, +// {-2,+2}, {-1, +2}, {0, +2}, {+1, +2}, {+2, +2}}; + + +static +const struct _spiral { + + int AdvX, AdvY; + + } Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1}, + {-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2}, + {+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2}, + {-1, +2}, {-2, +2}, {-2, +1}, {-2, 0}, {-2, -1}, {-2, -2} }; + +#define NSTEPS (sizeof(Spiral) / sizeof(struct _spiral)) + +static +int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[]) +{ + int nSectors = 0; + int a, t; + cmsUInt32Number i; + cmsGDBPoint* pt; + + for (i=0; i < NSTEPS; i++) { + + a = alpha + Spiral[i].AdvX; + t = theta + Spiral[i].AdvY; + + // Cycle at the end + a %= SECTORS; + t %= SECTORS; + + // Cycle at the begin + if (a < 0) a = SECTORS + a; + if (t < 0) t = SECTORS + t; + + pt = &gbd ->Gamut[t][a]; + + if (pt -> Type != GP_EMPTY) { + + Close[nSectors++] = pt; + } + } + + return nSectors; +} + + +// Interpolate a missing sector. Method identifies whatever this is top, bottom or mid +static +cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta) +{ + cmsSpherical sp; + cmsVEC3 Lab; + cmsVEC3 Centre; + cmsLine ray; + int nCloseSectors; + cmsGDBPoint* Close[NSTEPS + 1]; + cmsSpherical closel, templ; + cmsLine edge; + int k, m; + + // Is that point already specified? + if (gbd ->Gamut[theta][alpha].Type != GP_EMPTY) return TRUE; + + // Fill close points + nCloseSectors = FindNearSectors(gbd, alpha, theta, Close); + + + // Find a central point on the sector + sp.alpha = (cmsFloat64Number) ((alpha + 0.5) * 360.0) / (SECTORS); + sp.theta = (cmsFloat64Number) ((theta + 0.5) * 180.0) / (SECTORS); + sp.r = 50.0; + + // Convert to Cartesian + ToCartesian(&Lab, &sp); + + // Create a ray line from centre to this point + _cmsVEC3init(&Centre, 50.0, 0, 0); + LineOf2Points(&ray, &Lab, &Centre); + + // For all close sectors + closel.r = 0.0; + closel.alpha = 0; + closel.theta = 0; + + for (k=0; k < nCloseSectors; k++) { + + for(m = k+1; m < nCloseSectors; m++) { + + cmsVEC3 temp, a1, a2; + + // A line from sector to sector + ToCartesian(&a1, &Close[k]->p); + ToCartesian(&a2, &Close[m]->p); + + LineOf2Points(&edge, &a1, &a2); + + // Find a line + ClosestLineToLine(&temp, &ray, &edge); + + // Convert to spherical + ToSpherical(&templ, &temp); + + + if ( templ.r > closel.r && + templ.theta >= (theta*180.0/SECTORS) && + templ.theta <= ((theta+1)*180.0/SECTORS) && + templ.alpha >= (alpha*360.0/SECTORS) && + templ.alpha <= ((alpha+1)*360.0/SECTORS)) { + + closel = templ; + } + } + } + + gbd ->Gamut[theta][alpha].p = closel; + gbd ->Gamut[theta][alpha].Type = GP_MODELED; + + return TRUE; + +} + + +// Interpolate missing parts. The algorithm fist computes slices at +// theta=0 and theta=Max. +cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags) +{ + int alpha, theta; + cmsGDB* gbd = (cmsGDB*) hGBD; + + _cmsAssert(hGBD != NULL); + + // Interpolate black + for (alpha = 0; alpha < SECTORS; alpha++) { + + if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE; + } + + // Interpolate white + for (alpha = 0; alpha < SECTORS; alpha++) { + + if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE; + } + + + // Interpolate Mid + for (theta = 1; theta < SECTORS; theta++) { + for (alpha = 0; alpha < SECTORS; alpha++) { + + if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE; + } + } + + // Done + return TRUE; + + cmsUNUSED_PARAMETER(dwFlags); +} + + + + +// -------------------------------------------------------------------------------------------------------- + +// Great for debug, but not suitable for real use + +#if 0 +cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) +{ + FILE* fp; + int i, j; + cmsGDB* gbd = (cmsGDB*) hGBD; + cmsGDBPoint* pt; + + fp = fopen (fname, "wt"); + if (fp == NULL) + return FALSE; + + fprintf (fp, "#VRML V2.0 utf8\n"); + + // set the viewing orientation and distance + fprintf (fp, "DEF CamTest Group {\n"); + fprintf (fp, "\tchildren [\n"); + fprintf (fp, "\t\tDEF Cameras Group {\n"); + fprintf (fp, "\t\t\tchildren [\n"); + fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n"); + fprintf (fp, "\t\t\t\t\tposition 0 0 340\n"); + fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n"); + fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n"); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t]\n"); + fprintf (fp, "\t\t},\n"); + fprintf (fp, "\t]\n"); + fprintf (fp, "}\n"); + + // Output the background stuff + fprintf (fp, "Background {\n"); + fprintf (fp, "\tskyColor [\n"); + fprintf (fp, "\t\t.5 .5 .5\n"); + fprintf (fp, "\t]\n"); + fprintf (fp, "}\n"); + + // Output the shape stuff + fprintf (fp, "Transform {\n"); + fprintf (fp, "\tscale .3 .3 .3\n"); + fprintf (fp, "\tchildren [\n"); + + // Draw the axes as a shape: + fprintf (fp, "\t\tShape {\n"); + fprintf (fp, "\t\t\tappearance Appearance {\n"); + fprintf (fp, "\t\t\t\tmaterial Material {\n"); + fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n"); + fprintf (fp, "\t\t\t\t\temissiveColor 1.0 1.0 1.0\n"); + fprintf (fp, "\t\t\t\t\tshininess 0.8\n"); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t}\n"); + fprintf (fp, "\t\t\tgeometry IndexedLineSet {\n"); + fprintf (fp, "\t\t\t\tcoord Coordinate {\n"); + fprintf (fp, "\t\t\t\t\tpoint [\n"); + fprintf (fp, "\t\t\t\t\t0.0 0.0 0.0,\n"); + fprintf (fp, "\t\t\t\t\t%f 0.0 0.0,\n", 255.0); + fprintf (fp, "\t\t\t\t\t0.0 %f 0.0,\n", 255.0); + fprintf (fp, "\t\t\t\t\t0.0 0.0 %f]\n", 255.0); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t\tcoordIndex [\n"); + fprintf (fp, "\t\t\t\t\t0, 1, -1\n"); + fprintf (fp, "\t\t\t\t\t0, 2, -1\n"); + fprintf (fp, "\t\t\t\t\t0, 3, -1]\n"); + fprintf (fp, "\t\t\t}\n"); + fprintf (fp, "\t\t}\n"); + + + fprintf (fp, "\t\tShape {\n"); + fprintf (fp, "\t\t\tappearance Appearance {\n"); + fprintf (fp, "\t\t\t\tmaterial Material {\n"); + fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n"); + fprintf (fp, "\t\t\t\t\temissiveColor 1 1 1\n"); + fprintf (fp, "\t\t\t\t\tshininess 0.8\n"); + fprintf (fp, "\t\t\t\t}\n"); + fprintf (fp, "\t\t\t}\n"); + fprintf (fp, "\t\t\tgeometry PointSet {\n"); + + // fill in the points here + fprintf (fp, "\t\t\t\tcoord Coordinate {\n"); + fprintf (fp, "\t\t\t\t\tpoint [\n"); + + // We need to transverse all gamut hull. + for (i=0; i < SECTORS; i++) + for (j=0; j < SECTORS; j++) { + + cmsVEC3 v; + + pt = &gbd ->Gamut[i][j]; + ToCartesian(&v, &pt ->p); + + fprintf (fp, "\t\t\t\t\t%g %g %g", v.n[0]+50, v.n[1], v.n[2]); + + if ((j == SECTORS - 1) && (i == SECTORS - 1)) + fprintf (fp, "]\n"); + else + fprintf (fp, ",\n"); + + } + + fprintf (fp, "\t\t\t\t}\n"); + + + + // fill in the face colors + fprintf (fp, "\t\t\t\tcolor Color {\n"); + fprintf (fp, "\t\t\t\t\tcolor [\n"); + + for (i=0; i < SECTORS; i++) + for (j=0; j < SECTORS; j++) { + + cmsVEC3 v; + + pt = &gbd ->Gamut[i][j]; + + + ToCartesian(&v, &pt ->p); + + + if (pt ->Type == GP_EMPTY) + fprintf (fp, "\t\t\t\t\t%g %g %g", 0.0, 0.0, 0.0); + else + if (pt ->Type == GP_MODELED) + fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, .5, .5); + else { + fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, 1.0, 1.0); + + } + + if ((j == SECTORS - 1) && (i == SECTORS - 1)) + fprintf (fp, "]\n"); + else + fprintf (fp, ",\n"); + } + fprintf (fp, "\t\t\t}\n"); + + + fprintf (fp, "\t\t\t}\n"); + fprintf (fp, "\t\t}\n"); + fprintf (fp, "\t]\n"); + fprintf (fp, "}\n"); + + fclose (fp); + + return TRUE; +} +#endif + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmstypes.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmstypes.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmstypes.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmstypes.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,5656 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Tag Serialization ----------------------------------------------------------------------------- +// This file implements every single tag and tag type as described in the ICC spec. Some types +// have been deprecated, like ncl and Data. There is no implementation for those types as there +// are no profiles holding them. The programmer can also extend this list by defining his own types +// by using the appropriate plug-in. There are three types of plug ins regarding that. First type +// allows to define new tags using any existing type. Next plug-in type allows to define new types +// and the third one is very specific: allows to extend the number of elements in the multiprocessing +// elements special type. +//-------------------------------------------------------------------------------------------------- + +// Some broken types +#define cmsCorbisBrokenXYZtype ((cmsTagTypeSignature) 0x17A505B8) +#define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00) + +// This is the linked list that keeps track of the defined types +typedef struct _cmsTagTypeLinkedList_st { + + cmsTagTypeHandler Handler; + struct _cmsTagTypeLinkedList_st* Next; + +} _cmsTagTypeLinkedList; + +// Some macros to define callbacks. +#define READ_FN(x) Type_##x##_Read +#define WRITE_FN(x) Type_##x##_Write +#define FREE_FN(x) Type_##x##_Free +#define DUP_FN(x) Type_##x##_Dup + +// Helper macro to define a handler. Callbacks do have a fixed naming convention. +#define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x), NULL, 0 } + +// Helper macro to define a MPE handler. Callbacks do have a fixed naming convention +#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 } + +// Infinites +#define MINUS_INF (-1E22F) +#define PLUS_INF (+1E22F) + + +// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head +static +cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos) +{ + cmsPluginTagType* Plugin = (cmsPluginTagType*) Data; + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos); + _cmsTagTypeLinkedList *pt; + + // Calling the function with NULL as plug-in would unregister the plug in. + if (Data == NULL) { + + // There is no need to set free the memory, as pool is destroyed as a whole. + ctx ->TagTypes = NULL; + return TRUE; + } + + // Registering happens in plug-in memory pool. + pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList)); + if (pt == NULL) return FALSE; + + pt ->Handler = Plugin ->Handler; + pt ->Next = ctx ->TagTypes; + + ctx ->TagTypes = pt; + + return TRUE; +} + +// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons +// made by plug-ins and then the built-in defaults. +static +cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList) +{ + _cmsTagTypeLinkedList* pt; + + for (pt = PluginLinkedList; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Handler.Signature) return &pt ->Handler; + } + + for (pt = DefaultLinkedList; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Handler.Signature) return &pt ->Handler; + } + + return NULL; +} + + +// Auxiliary to convert UTF-32 to UTF-16 in some cases +static +cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array) +{ + cmsUInt32Number i; + + _cmsAssert(io != NULL); + _cmsAssert(!(Array == NULL && n > 0)); + + for (i=0; i < n; i++) { + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE; + } + + return TRUE; +} + +// Auxiliary to read an array of wchar_t +static +cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) +{ + cmsUInt32Number i; + cmsUInt16Number tmp; + + _cmsAssert(io != NULL); + + for (i=0; i < n; i++) { + + if (Array != NULL) { + + if (!_cmsReadUInt16Number(io, &tmp)) return FALSE; + Array[i] = (wchar_t) tmp; + } + else { + if (!_cmsReadUInt16Number(io, NULL)) return FALSE; + } + + } + return TRUE; +} + +// To deal with position tables +typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag); + +// Helper function to deal with position tables as described in ICC spec 4.3 +// A table of n elements is read, where first comes n records containing offsets and sizes and +// then a block containing the data itself. This allows to reuse same data in more than one entry +static +cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number Count, + cmsUInt32Number BaseOffset, + void *Cargo, + PositionTableEntryFn ElementFn) +{ + cmsUInt32Number i; + cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; + cmsUInt32Number currentPosition; + + currentPosition = io->Tell(io); + + // Verify there is enough space left to read at least two cmsUInt32Number items for Count items. + if (((io->ReportedSize - currentPosition) / (2 * sizeof(cmsUInt32Number))) < Count) + return FALSE; + + // Let's take the offsets to each element + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); + if (ElementOffsets == NULL) goto Error; + + ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); + if (ElementSizes == NULL) goto Error; + + for (i=0; i < Count; i++) { + + if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error; + if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error; + + ElementOffsets[i] += BaseOffset; + } + + // Seek to each element and read it + for (i=0; i < Count; i++) { + + if (!io -> Seek(io, ElementOffsets[i])) goto Error; + + // This is the reader callback + if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error; + } + + // Success + if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + return TRUE; + +Error: + if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + return FALSE; +} + +// Same as anterior, but for write position tables +static +cmsBool WritePositionTable(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number SizeOfTag, + cmsUInt32Number Count, + cmsUInt32Number BaseOffset, + void *Cargo, + PositionTableEntryFn ElementFn) +{ + cmsUInt32Number i; + cmsUInt32Number DirectoryPos, CurrentPos, Before; + cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; + + // Create table + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); + if (ElementOffsets == NULL) goto Error; + + ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); + if (ElementSizes == NULL) goto Error; + + // Keep starting position of curve offsets + DirectoryPos = io ->Tell(io); + + // Write a fake directory to be filled latter on + for (i=0; i < Count; i++) { + + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size + } + + // Write each element. Keep track of the size as well. + for (i=0; i < Count; i++) { + + Before = io ->Tell(io); + ElementOffsets[i] = Before - BaseOffset; + + // Callback to write... + if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error; + + // Now the size + ElementSizes[i] = io ->Tell(io) - Before; + } + + // Write the directory + CurrentPos = io ->Tell(io); + if (!io ->Seek(io, DirectoryPos)) goto Error; + + for (i=0; i < Count; i++) { + if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; + if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; + } + + if (!io ->Seek(io, CurrentPos)) goto Error; + + if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + return TRUE; + +Error: + if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes); + return FALSE; +} + + +// ******************************************************************************** +// Type XYZ. Only one value is allowed +// ******************************************************************************** + +//The XYZType contains an array of three encoded values for the XYZ tristimulus +//values. Tristimulus values must be non-negative. The signed encoding allows for +//implementation optimizations by minimizing the number of fixed formats. + + +static +void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsCIEXYZ* xyz; + + *nItems = 0; + xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ)); + if (xyz == NULL) return NULL; + + if (!_cmsReadXYZNumber(io, xyz)) { + _cmsFree(self ->ContextID, xyz); + return NULL; + } + + *nItems = 1; + return (void*) xyz; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr); + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ)); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +static +cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data) +{ + return cmsSigXYZType; + + cmsUNUSED_PARAMETER(ICCVersion); + cmsUNUSED_PARAMETER(Data); +} + + +// ******************************************************************************** +// Type chromaticity. Only one value is allowed +// ******************************************************************************** +// The chromaticity tag type provides basic chromaticity data and type of +// phosphors or colorants of a monitor to applications and utilities. + +static +void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsCIExyYTRIPLE* chrm; + cmsUInt16Number nChans, Table; + + *nItems = 0; + chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE)); + if (chrm == NULL) return NULL; + + if (!_cmsReadUInt16Number(io, &nChans)) goto Error; + + // Let's recover from a bug introduced in early versions of lcms1 + if (nChans == 0 && SizeOfTag == 32) { + + if (!_cmsReadUInt16Number(io, NULL)) goto Error; + if (!_cmsReadUInt16Number(io, &nChans)) goto Error; + } + + if (nChans != 3) goto Error; + + if (!_cmsReadUInt16Number(io, &Table)) goto Error; + + if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error; + if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error; + + chrm ->Red.Y = 1.0; + + if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error; + if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error; + + chrm ->Green.Y = 1.0; + + if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error; + if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error; + + chrm ->Blue.Y = 1.0; + + *nItems = 1; + return (void*) chrm; + +Error: + _cmsFree(self ->ContextID, (void*) chrm); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io) +{ + if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) _cmsDoubleTo15Fixed16(x))) return FALSE; + if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) _cmsDoubleTo15Fixed16(y))) return FALSE; + + return TRUE; +} + +static +cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr; + + if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table + + if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE; + if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE; + if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE)); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigColorantOrderType +// ******************************************************************************** + +// This is an optional tag which specifies the laydown order in which colorants will +// be printed on an n-colorant device. The laydown order may be the same as the +// channel generation order listed in the colorantTableTag or the channel order of a +// colour space such as CMYK, in which case this tag is not needed. When this is not +// the case (for example, ink-towers sometimes use the order KCMY), this tag may be +// used to specify the laydown order of the colorants. + + +static +void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt8Number* ColorantOrder; + cmsUInt32Number Count; + + *nItems = 0; + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + if (Count > cmsMAXCHANNELS) return NULL; + + ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number)); + if (ColorantOrder == NULL) return NULL; + + // We use FF as end marker + memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number)); + + if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) { + + _cmsFree(self ->ContextID, (void*) ColorantOrder); + return NULL; + } + + *nItems = 1; + return (void*) ColorantOrder; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr; + cmsUInt32Number i, sz, Count; + + // Get the length + for (Count=i=0; i < cmsMAXCHANNELS; i++) { + if (ColorantOrder[i] != 0xFF) Count++; + } + + if (!_cmsWriteUInt32Number(io, Count)) return FALSE; + + sz = Count * sizeof(cmsUInt8Number); + if (!io -> Write(io, sz, ColorantOrder)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number)); + + cmsUNUSED_PARAMETER(n); +} + + +static +void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigS15Fixed16ArrayType +// ******************************************************************************** +// This type represents an array of generic 4-byte/32-bit fixed point quantity. +// The number of values is determined from the size of the tag. + +static +void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsFloat64Number* array_double; + cmsUInt32Number i, n; + + *nItems = 0; + n = SizeOfTag / sizeof(cmsUInt32Number); + array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number)); + if (array_double == NULL) return NULL; + + for (i=0; i < n; i++) { + + if (!_cmsRead15Fixed16Number(io, &array_double[i])) { + + _cmsFree(self ->ContextID, array_double); + return NULL; + } + } + + *nItems = n; + return (void*) array_double; +} + +static +cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsFloat64Number* Value = (cmsFloat64Number*) Ptr; + cmsUInt32Number i; + + for (i=0; i < nItems; i++) { + + if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number)); +} + + +static +void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigU16Fixed16ArrayType +// ******************************************************************************** +// This type represents an array of generic 4-byte/32-bit quantity. +// The number of values is determined from the size of the tag. + + +static +void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsFloat64Number* array_double; + cmsUInt32Number v; + cmsUInt32Number i, n; + + *nItems = 0; + n = SizeOfTag / sizeof(cmsUInt32Number); + array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number)); + if (array_double == NULL) return NULL; + + for (i=0; i < n; i++) { + + if (!_cmsReadUInt32Number(io, &v)) { + _cmsFree(self ->ContextID, (void*) array_double); + return NULL; + } + + // Convert to cmsFloat64Number + array_double[i] = (cmsFloat64Number) (v / 65536.0); + } + + *nItems = n; + return (void*) array_double; +} + +static +cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsFloat64Number* Value = (cmsFloat64Number*) Ptr; + cmsUInt32Number i; + + for (i=0; i < nItems; i++) { + + cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5); + + if (!_cmsWriteUInt32Number(io, v)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number)); +} + +static +void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigSignatureType +// ******************************************************************************** +// +// The signatureType contains a four-byte sequence, Sequences of less than four +// characters are padded at the end with spaces, 20h. +// Typically this type is used for registered tags that can be displayed on many +// development systems as a sequence of four characters. + +static +void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature)); + if (SigPtr == NULL) return NULL; + + if (!_cmsReadUInt32Number(io, SigPtr)) return NULL; + *nItems = 1; + + return SigPtr; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsSignature* SigPtr = (cmsSignature*) Ptr; + + return _cmsWriteUInt32Number(io, *SigPtr); + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature)); +} + +static +void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigTextType +// ******************************************************************************** +// +// The textType is a simple text structure that contains a 7-bit ASCII text string. +// The length of the string is obtained by subtracting 8 from the element size portion +// of the tag itself. This string must be terminated with a 00h byte. + +static +void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + char* Text = NULL; + cmsMLU* mlu = NULL; + + // Create a container + mlu = cmsMLUalloc(self ->ContextID, 1); + if (mlu == NULL) return NULL; + + *nItems = 0; + + // We need to store the "\0" at the end, so +1 + if (SizeOfTag == UINT_MAX) goto Error; + + Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); + if (Text == NULL) goto Error; + + if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error; + + // Make sure text is properly ended + Text[SizeOfTag] = 0; + *nItems = 1; + + // Keep the result + if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error; + + _cmsFree(self ->ContextID, Text); + return (void*) mlu; + +Error: + if (mlu != NULL) + cmsMLUfree(mlu); + if (Text != NULL) + _cmsFree(self ->ContextID, Text); + + return NULL; +} + +// The conversion implies to choose a language. So, we choose the actual language. +static +cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsMLU* mlu = (cmsMLU*) Ptr; + cmsUInt32Number size; + cmsBool rc; + char* Text; + + // Get the size of the string. Note there is an extra "\0" at the end + size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); + if (size == 0) return FALSE; // Cannot be zero! + + // Create memory + Text = (char*) _cmsMalloc(self ->ContextID, size); + if (Text == NULL) return FALSE; + + cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size); + + // Write it, including separator + rc = io ->Write(io, size, Text); + + _cmsFree(self ->ContextID, Text); + return rc; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsMLUdup((cmsMLU*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + + +static +void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsMLU* mlu = (cmsMLU*) Ptr; + cmsMLUfree(mlu); + return; + + cmsUNUSED_PARAMETER(self); +} + +static +cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data) +{ + if (ICCVersion >= 4.0) + return cmsSigMultiLocalizedUnicodeType; + + return cmsSigTextType; + + cmsUNUSED_PARAMETER(Data); +} + + +// ******************************************************************************** +// Type cmsSigDataType +// ******************************************************************************** + +// General purpose data type +static +void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsICCData* BinData; + cmsUInt32Number LenOfData; + + *nItems = 0; + + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + + LenOfData = SizeOfTag - sizeof(cmsUInt32Number); + if (LenOfData > INT_MAX) return NULL; + + BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1); + if (BinData == NULL) return NULL; + + BinData ->len = LenOfData; + if (!_cmsReadUInt32Number(io, &BinData->flag)) { + _cmsFree(self ->ContextID, BinData); + return NULL; + } + + if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) { + + _cmsFree(self ->ContextID, BinData); + return NULL; + } + + *nItems = 1; + + return (void*) BinData; +} + + +static +cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsICCData* BinData = (cmsICCData*) Ptr; + + if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE; + + return io ->Write(io, BinData ->len, BinData ->data); + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + cmsICCData* BinData = (cmsICCData*) Ptr; + + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigTextDescriptionType +// ******************************************************************************** + +static +void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + char* Text = NULL; + cmsMLU* mlu = NULL; + cmsUInt32Number AsciiCount; + cmsUInt32Number i, UnicodeCode, UnicodeCount; + cmsUInt16Number ScriptCodeCode, Dummy; + cmsUInt8Number ScriptCodeCount; + + *nItems = 0; + + // One dword should be there + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + + // Read len of ASCII + if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + // Check for size + if (SizeOfTag < AsciiCount) return NULL; + + // All seems Ok, allocate the container + mlu = cmsMLUalloc(self ->ContextID, 1); + if (mlu == NULL) return NULL; + + // As many memory as size of tag + Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1); + if (Text == NULL) goto Error; + + // Read it + if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error; + SizeOfTag -= AsciiCount; + + // Make sure there is a terminator + Text[AsciiCount] = 0; + + // Set the MLU entry. From here we can be tolerant to wrong types + if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error; + _cmsFree(self ->ContextID, (void*) Text); + Text = NULL; + + // Skip Unicode code + if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done; + if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done; + if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done; + SizeOfTag -= 2* sizeof(cmsUInt32Number); + + if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done; + + for (i=0; i < UnicodeCount; i++) { + if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done; + } + SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number); + + // Skip ScriptCode code if present. Some buggy profiles does have less + // data that stricttly required. We need to skip it as this type may come + // embedded in other types. + + if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) { + + if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done; + if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done; + + // Skip rest of tag + for (i=0; i < 67; i++) { + if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error; + } + } + +Done: + + *nItems = 1; + return mlu; + +Error: + if (Text) _cmsFree(self ->ContextID, (void*) Text); + if (mlu) cmsMLUfree(mlu); + return NULL; +} + + +// This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it +static +cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsMLU* mlu = (cmsMLU*) Ptr; + char *Text = NULL; + wchar_t *Wide = NULL; + cmsUInt32Number len, len_text, len_tag_requirement, len_aligned; + cmsBool rc = FALSE; + char Filler[68]; + + // Used below for writing zeroes + memset(Filler, 0, sizeof(Filler)); + + // Get the len of string + len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); + + // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data + //(see clause 4.1 for the definition of 'aligned'). Because the Unicode language + // code and Unicode count immediately follow the ASCII description, their + // alignment is not correct if the ASCII count is not a multiple of four. The + // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and + // writing software must be written carefully in order to handle these alignment + // problems. + // + // The above last sentence suggest to handle alignment issues in the + // parser. The provided example (Table 69 on Page 60) makes this clear. + // The padding only in the ASCII count is not sufficient for a aligned tag + // size, with the same text size in ASCII and Unicode. + + // Null strings + if (len <= 0) { + + Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char)); + Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t)); + } + else { + // Create independent buffers + Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char)); + if (Text == NULL) goto Error; + + Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t)); + if (Wide == NULL) goto Error; + + // Get both representations. + cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char)); + cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t)); + } + + // Tell the real text len including the null terminator and padding + len_text = (cmsUInt32Number) strlen(Text) + 1; + // Compute an total tag size requirement + len_tag_requirement = (8+4+len_text+4+4+2*len_text+2+1+67); + len_aligned = _cmsALIGNLONG(len_tag_requirement); + + // * cmsUInt32Number count; * Description length + // * cmsInt8Number desc[count] * NULL terminated ascii string + // * cmsUInt32Number ucLangCode; * UniCode language code + // * cmsUInt32Number ucCount; * UniCode description length + // * cmsInt16Number ucDesc[ucCount];* The UniCode description + // * cmsUInt16Number scCode; * ScriptCode code + // * cmsUInt8Number scCount; * ScriptCode count + // * cmsInt8Number scDesc[67]; * ScriptCode Description + + if (!_cmsWriteUInt32Number(io, len_text)) goto Error; + if (!io ->Write(io, len_text, Text)) goto Error; + + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode + + if (!_cmsWriteUInt32Number(io, len_text)) goto Error; + // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t) + if (!_cmsWriteWCharArray(io, len_text, Wide)) goto Error; + + // ScriptCode Code & count (unused) + if (!_cmsWriteUInt16Number(io, 0)) goto Error; + if (!_cmsWriteUInt8Number(io, 0)) goto Error; + + if (!io ->Write(io, 67, Filler)) goto Error; + + // possibly add pad at the end of tag + if(len_aligned - len_tag_requirement > 0) + if (!io ->Write(io, len_aligned - len_tag_requirement, Filler)) goto Error; + + rc = TRUE; + +Error: + if (Text) _cmsFree(self ->ContextID, Text); + if (Wide) _cmsFree(self ->ContextID, Wide); + + return rc; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsMLUdup((cmsMLU*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsMLU* mlu = (cmsMLU*) Ptr; + + cmsMLUfree(mlu); + return; + + cmsUNUSED_PARAMETER(self); +} + + +static +cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data) +{ + if (ICCVersion >= 4.0) + return cmsSigMultiLocalizedUnicodeType; + + return cmsSigTextDescriptionType; + + cmsUNUSED_PARAMETER(Data); +} + + +// ******************************************************************************** +// Type cmsSigCurveType +// ******************************************************************************** + +static +void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number Count; + cmsToneCurve* NewGamma; + + *nItems = 0; + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + switch (Count) { + + case 0: // Linear. + { + cmsFloat64Number SingleGamma = 1.0; + + NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma); + if (!NewGamma) return NULL; + *nItems = 1; + return NewGamma; + } + + case 1: // Specified as the exponent of gamma function + { + cmsUInt16Number SingleGammaFixed; + cmsFloat64Number SingleGamma; + + if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL; + SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed); + + *nItems = 1; + return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma); + } + + default: // Curve + + if (Count > 0x7FFF) + return NULL; // This is to prevent bad guys for doing bad things + + NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL); + if (!NewGamma) return NULL; + + if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) { + cmsFreeToneCurve(NewGamma); + return NULL; + } + + *nItems = 1; + return NewGamma; + } + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsToneCurve* Curve = (cmsToneCurve*) Ptr; + + if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) { + + // Single gamma, preserve number + cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]); + + if (!_cmsWriteUInt32Number(io, 1)) return FALSE; + if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE; + return TRUE; + + } + + if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE; + return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16); + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsToneCurve* gamma = (cmsToneCurve*) Ptr; + + cmsFreeToneCurve(gamma); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigParametricCurveType +// ******************************************************************************** + + +// Decide which curve type to use on writing +static +cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data) +{ + cmsToneCurve* Curve = (cmsToneCurve*) Data; + + if (ICCVersion < 4.0) return cmsSigCurveType; + if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric + if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves + if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves + + return cmsSigParametricCurveType; +} + +static +void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + static const int ParamsByType[] = { 1, 3, 4, 5, 7 }; + cmsFloat64Number Params[10]; + cmsUInt16Number Type; + int i, n; + cmsToneCurve* NewGamma; + + if (!_cmsReadUInt16Number(io, &Type)) return NULL; + if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved + + if (Type > 4) { + + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type); + return NULL; + } + + memset(Params, 0, sizeof(Params)); + n = ParamsByType[Type]; + + for (i=0; i < n; i++) { + + if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL; + } + + NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params); + + *nItems = 1; + return NewGamma; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsToneCurve* Curve = (cmsToneCurve*) Ptr; + int i, nParams, typen; + static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 }; + + typen = Curve -> Segments[0].Type; + + if (Curve ->nSegments > 1 || typen < 1) { + + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written"); + return FALSE; + } + + if (typen > 5) { + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve"); + return FALSE; + } + + nParams = ParamsByType[typen]; + + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE; + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved + + for (i=0; i < nParams; i++) { + + if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsToneCurve* gamma = (cmsToneCurve*) Ptr; + + cmsFreeToneCurve(gamma); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigDateTimeType +// ******************************************************************************** + +// A 12-byte value representation of the time and date, where the byte usage is assigned +// as specified in table 1. The actual values are encoded as 16-bit unsigned integers +// (uInt16Number - see 5.1.6). +// +// All the dateTimeNumber values in a profile shall be in Coordinated Universal Time +// (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local +// time to UTC when setting these values. Programmes that display these values may show +// the dateTimeNumber as UTC, show the equivalent local time (at current locale), or +// display both UTC and local versions of the dateTimeNumber. + +static +void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsDateTimeNumber timestamp; + struct tm * NewDateTime; + + *nItems = 0; + NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm)); + if (NewDateTime == NULL) return NULL; + + if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL; + + _cmsDecodeDateTimeNumber(×tamp, NewDateTime); + + *nItems = 1; + return NewDateTime; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + struct tm * DateTime = (struct tm*) Ptr; + cmsDateTimeNumber timestamp; + + _cmsEncodeDateTimeNumber(×tamp, DateTime); + if (!io ->Write(io, sizeof(cmsDateTimeNumber), ×tamp)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm)); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + + +// ******************************************************************************** +// Type icMeasurementType +// ******************************************************************************** + +/* +The measurementType information refers only to the internal profile data and is +meant to provide profile makers an alternative to the default measurement +specifications. +*/ + +static +void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsICCMeasurementConditions mc; + + + memset(&mc, 0, sizeof(mc)); + + if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL; + if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL; + if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL; + if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL; + if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL; + + *nItems = 1; + return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions)); + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr; + + if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE; + if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE; + if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE; + if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions)); + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigMultiLocalizedUnicodeType +// ******************************************************************************** +// +// Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from +// Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be +// taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance) +// + +static +void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsMLU* mlu; + cmsUInt32Number Count, RecLen, NumOfWchar; + cmsUInt32Number SizeOfHeader; + cmsUInt32Number Len, Offset; + cmsUInt32Number i; + wchar_t* Block; + cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition; + + *nItems = 0; + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + if (!_cmsReadUInt32Number(io, &RecLen)) return NULL; + + if (RecLen != 12) { + + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported."); + return NULL; + } + + mlu = cmsMLUalloc(self ->ContextID, Count); + if (mlu == NULL) return NULL; + + mlu ->UsedEntries = Count; + + SizeOfHeader = 12 * Count + sizeof(_cmsTagBase); + LargestPosition = 0; + + for (i=0; i < Count; i++) { + + if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error; + if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error; + + // Now deal with Len and offset. + if (!_cmsReadUInt32Number(io, &Len)) goto Error; + if (!_cmsReadUInt32Number(io, &Offset)) goto Error; + + // Check for overflow + if (Offset < (SizeOfHeader + 8)) goto Error; + if (((Offset + Len) < Len) || ((Offset + Len) > SizeOfTag + 8)) goto Error; + + // True begin of the string + BeginOfThisString = Offset - SizeOfHeader - 8; + + // Adjust to wchar_t elements + mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + + // To guess maximum size, add offset + len + EndOfThisString = BeginOfThisString + Len; + if (EndOfThisString > LargestPosition) + LargestPosition = EndOfThisString; + } + + // Now read the remaining of tag and fill all strings. Subtract the directory + SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + if (SizeOfTag == 0) + { + Block = NULL; + NumOfWchar = 0; + + } + else + { + Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag); + if (Block == NULL) goto Error; + NumOfWchar = SizeOfTag / sizeof(wchar_t); + if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error; + } + + mlu ->MemPool = Block; + mlu ->PoolSize = SizeOfTag; + mlu ->PoolUsed = SizeOfTag; + + *nItems = 1; + return (void*) mlu; + +Error: + if (mlu) cmsMLUfree(mlu); + return NULL; +} + +static +cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsMLU* mlu =(cmsMLU*) Ptr; + cmsUInt32Number HeaderSize; + cmsUInt32Number Len, Offset; + cmsUInt32Number i; + + if (Ptr == NULL) { + + // Empty placeholder + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 12)) return FALSE; + return TRUE; + } + + if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE; + if (!_cmsWriteUInt32Number(io, 12)) return FALSE; + + HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase); + + for (i=0; i < mlu ->UsedEntries; i++) { + + Len = mlu ->Entries[i].Len; + Offset = mlu ->Entries[i].StrW; + + Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t); + Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8; + + if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE; + if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE; + if (!_cmsWriteUInt32Number(io, Len)) return FALSE; + if (!_cmsWriteUInt32Number(io, Offset)) return FALSE; + } + + if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsMLUdup((cmsMLU*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsMLUfree((cmsMLU*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigLut8Type +// ******************************************************************************** + +// Decide which LUT type to use on writing +static +cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data) +{ + cmsPipeline* Lut = (cmsPipeline*) Data; + + if (ICCVersion < 4.0) { + if (Lut ->SaveAs8Bits) return cmsSigLut8Type; + return cmsSigLut16Type; + } + else { + return cmsSigLutAtoBType; + } +} + +static +cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data) +{ + cmsPipeline* Lut = (cmsPipeline*) Data; + + if (ICCVersion < 4.0) { + if (Lut ->SaveAs8Bits) return cmsSigLut8Type; + return cmsSigLut16Type; + } + else { + return cmsSigLutBtoAType; + } +} + +/* +This structure represents a colour transform using tables of 8-bit precision. +This type contains four processing elements: a 3 by 3 matrix (which shall be +the identity matrix unless the input colour space is XYZ), a set of one dimensional +input tables, a multidimensional lookup table, and a set of one dimensional output +tables. Data is processed using these elements via the following sequence: +(matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables) + +Byte Position Field Length (bytes) Content Encoded as... +8 1 Number of Input Channels (i) uInt8Number +9 1 Number of Output Channels (o) uInt8Number +10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number +11 1 Reserved for padding (fill with 00h) + +12..15 4 Encoded e00 parameter s15Fixed16Number +*/ + + +// Read 8 bit tables as gamma functions +static +cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, cmsUInt32Number nChannels) +{ + cmsUInt8Number* Temp = NULL; + cmsUInt32Number i, j; + cmsToneCurve* Tables[cmsMAXCHANNELS]; + + if (nChannels > cmsMAXCHANNELS) return FALSE; + if (nChannels <= 0) return FALSE; + + memset(Tables, 0, sizeof(Tables)); + + Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256); + if (Temp == NULL) return FALSE; + + for (i=0; i < nChannels; i++) { + Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); + if (Tables[i] == NULL) goto Error; + } + + for (i=0; i < nChannels; i++) { + + if (io ->Read(io, Temp, 256, 1) != 1) goto Error; + + for (j=0; j < 256; j++) + Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]); + } + + _cmsFree(ContextID, Temp); + Temp = NULL; + + if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) + goto Error; + + for (i=0; i < nChannels; i++) + cmsFreeToneCurve(Tables[i]); + + return TRUE; + +Error: + for (i=0; i < nChannels; i++) { + if (Tables[i]) cmsFreeToneCurve(Tables[i]); + } + + if (Temp) _cmsFree(ContextID, Temp); + return FALSE; +} + + +static +cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables) +{ + int j; + cmsUInt32Number i; + cmsUInt8Number val; + + for (i=0; i < n; i++) { + + if (Tables) { + + // Usual case of identity curves + if ((Tables ->TheCurves[i]->nEntries == 2) && + (Tables->TheCurves[i]->Table16[0] == 0) && + (Tables->TheCurves[i]->Table16[1] == 65535)) { + + for (j=0; j < 256; j++) { + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE; + } + } + else + if (Tables ->TheCurves[i]->nEntries != 256) { + cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization"); + return FALSE; + } + else + for (j=0; j < 256; j++) { + + val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); + + if (!_cmsWriteUInt8Number(io, val)) return FALSE; + } + } + } + return TRUE; +} + + +// Check overflow +static +cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) +{ + cmsUInt32Number rv = 1, rc; + + if (a == 0) return 0; + if (n == 0) return 0; + + for (; b > 0; b--) { + + rv *= a; + + // Check for overflow + if (rv > UINT_MAX / a) return (cmsUInt32Number) -1; + + } + + rc = rv * n; + + if (rv != rc / n) return (cmsUInt32Number) -1; + return rc; +} + + +// That will create a MPE LUT with Matrix, pre tables, CLUT and post tables. +// 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust +// PCS on BToAxx tags and AtoB if abstract. We need to fix input direction. + +static +void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; + cmsUInt8Number* Temp = NULL; + cmsPipeline* NewLUT = NULL; + cmsUInt32Number nTabSize, i; + cmsFloat64Number Matrix[3*3]; + + *nItems = 0; + + if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error; + if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error; + if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error; + + if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least + + // Padding + if (!_cmsReadUInt8Number(io, NULL)) goto Error; + + // Do some checking + if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; + if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; + + // Allocates an empty Pipeline + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); + if (NewLUT == NULL) goto Error; + + // Read the Matrix + if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; + + + // Only operates if not identity... + if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { + + if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) + goto Error; + } + + // Get input tables + if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error; + + // Get 3D CLUT. Check the overflow.... + nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); + if (nTabSize == (cmsUInt32Number) -1) goto Error; + if (nTabSize > 0) { + + cmsUInt16Number *PtrW, *T; + + PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); + if (T == NULL) goto Error; + + Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize); + if (Temp == NULL) { + _cmsFree(self ->ContextID, T); + goto Error; + } + + if (io ->Read(io, Temp, nTabSize, 1) != 1) { + _cmsFree(self ->ContextID, T); + _cmsFree(self ->ContextID, Temp); + goto Error; + } + + for (i = 0; i < nTabSize; i++) { + + *PtrW++ = FROM_8_TO_16(Temp[i]); + } + _cmsFree(self ->ContextID, Temp); + Temp = NULL; + + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) { + _cmsFree(self ->ContextID, T); + goto Error; + } + _cmsFree(self ->ContextID, T); + } + + + // Get output tables + if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error; + + *nItems = 1; + return NewLUT; + +Error: + if (NewLUT != NULL) cmsPipelineFree(NewLUT); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +// We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin. +static +cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number j, nTabSize, i, n; + cmsUInt8Number val; + cmsPipeline* NewLUT = (cmsPipeline*) Ptr; + cmsStage* mpe; + _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; + _cmsStageMatrixData* MatMPE = NULL; + _cmsStageCLutData* clut = NULL; + cmsUInt32Number clutPoints; + + // Disassemble the LUT into components. + mpe = NewLUT -> Elements; + if (mpe ->Type == cmsSigMatrixElemType) { + + if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE; + MatMPE = (_cmsStageMatrixData*) mpe ->Data; + mpe = mpe -> Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { + PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; + mpe = mpe -> Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { + clut = (_cmsStageCLutData*) mpe -> Data; + mpe = mpe ->Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { + PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; + mpe = mpe -> Next; + } + + // That should be all + if (mpe != NULL) { + cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8"); + return FALSE; + } + + if (clut == NULL) + clutPoints = 0; + else + clutPoints = clut->Params->nSamples[0]; + + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding + + n = NewLUT->InputChannels * NewLUT->OutputChannels; + + if (MatMPE != NULL) { + + for (i = 0; i < 9; i++) + { + if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE; + } + } + else { + + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + } + + // The prelinearization table + if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE; + + nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels); + if (nTabSize == (cmsUInt32Number) -1) return FALSE; + if (nTabSize > 0) { + + // The 3D CLUT. + if (clut != NULL) { + + for (j=0; j < nTabSize; j++) { + + val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); + if (!_cmsWriteUInt8Number(io, val)) return FALSE; + } + } + } + + // The postlinearization table + if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + +// ******************************************************************************** +// Type cmsSigLut16Type +// ******************************************************************************** + +// Read 16 bit tables as gamma functions +static +cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, + cmsUInt32Number nChannels, cmsUInt32Number nEntries) +{ + cmsUInt32Number i; + cmsToneCurve* Tables[cmsMAXCHANNELS]; + + // Maybe an empty table? (this is a lcms extension) + if (nEntries <= 0) return TRUE; + + // Check for malicious profiles + if (nEntries < 2) return FALSE; + if (nChannels > cmsMAXCHANNELS) return FALSE; + + // Init table to zero + memset(Tables, 0, sizeof(Tables)); + + for (i=0; i < nChannels; i++) { + + Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL); + if (Tables[i] == NULL) goto Error; + + if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error; + } + + + // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code) + if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) + goto Error; + + for (i=0; i < nChannels; i++) + cmsFreeToneCurve(Tables[i]); + + return TRUE; + +Error: + for (i=0; i < nChannels; i++) { + if (Tables[i]) cmsFreeToneCurve(Tables[i]); + } + + return FALSE; +} + +static +cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables) +{ + cmsUInt32Number j; + cmsUInt32Number i; + cmsUInt16Number val; + cmsUInt32Number nEntries; + + _cmsAssert(Tables != NULL); + + nEntries = Tables->TheCurves[0]->nEntries; + + for (i=0; i < Tables ->nCurves; i++) { + + for (j=0; j < nEntries; j++) { + + val = Tables->TheCurves[i]->Table16[j]; + if (!_cmsWriteUInt16Number(io, val)) return FALSE; + } + } + return TRUE; + + cmsUNUSED_PARAMETER(ContextID); +} + +static +void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; + cmsPipeline* NewLUT = NULL; + cmsUInt32Number nTabSize; + cmsFloat64Number Matrix[3*3]; + cmsUInt16Number InputEntries, OutputEntries; + + *nItems = 0; + + if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL; + if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL; + if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum + + // Padding + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + + // Do some checking + if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; + if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); + if (NewLUT == NULL) goto Error; + + // Read the Matrix + if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; + if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; + + + // Only operates on 3 channels + if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { + + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) + goto Error; + } + + if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error; + if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error; + + if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error; + if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least + + // Get input tables + if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error; + + // Get 3D CLUT + nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); + if (nTabSize == (cmsUInt32Number) -1) goto Error; + if (nTabSize > 0) { + + cmsUInt16Number *T; + + T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); + if (T == NULL) goto Error; + + if (!_cmsReadUInt16Array(io, nTabSize, T)) { + _cmsFree(self ->ContextID, T); + goto Error; + } + + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) { + _cmsFree(self ->ContextID, T); + goto Error; + } + _cmsFree(self ->ContextID, T); + } + + + // Get output tables + if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error; + + *nItems = 1; + return NewLUT; + +Error: + if (NewLUT != NULL) cmsPipelineFree(NewLUT); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +// We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin. +// Some empty defaults are created for missing parts + +static +cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number nTabSize; + cmsPipeline* NewLUT = (cmsPipeline*) Ptr; + cmsStage* mpe; + _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; + _cmsStageMatrixData* MatMPE = NULL; + _cmsStageCLutData* clut = NULL; + cmsUInt32Number i, InputChannels, OutputChannels, clutPoints; + + // Disassemble the LUT into components. + mpe = NewLUT -> Elements; + if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) { + + MatMPE = (_cmsStageMatrixData*) mpe ->Data; + if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE; + mpe = mpe -> Next; + } + + + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { + PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; + mpe = mpe -> Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { + clut = (_cmsStageCLutData*) mpe -> Data; + mpe = mpe ->Next; + } + + if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { + PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; + mpe = mpe -> Next; + } + + // That should be all + if (mpe != NULL) { + cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16"); + return FALSE; + } + + InputChannels = cmsPipelineInputChannels(NewLUT); + OutputChannels = cmsPipelineOutputChannels(NewLUT); + + if (clut == NULL) + clutPoints = 0; + else + clutPoints = clut->Params->nSamples[0]; + + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding + + if (MatMPE != NULL) { + + for (i = 0; i < 9; i++) + { + if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE; + } + + } + else { + + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; + } + + + if (PreMPE != NULL) { + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE; + } else { + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; + } + + if (PostMPE != NULL) { + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE; + } else { + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; + + } + + // The prelinearization table + + if (PreMPE != NULL) { + if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE; + } + else { + for (i=0; i < InputChannels; i++) { + + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; + } + } + + nTabSize = uipow(OutputChannels, clutPoints, InputChannels); + if (nTabSize == (cmsUInt32Number) -1) return FALSE; + if (nTabSize > 0) { + // The 3D CLUT. + if (clut != NULL) { + if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; + } + } + + // The postlinearization table + if (PostMPE != NULL) { + if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE; + } + else { + for (i=0; i < OutputChannels; i++) { + + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; + } + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigLutAToBType +// ******************************************************************************** + + +// V4 stuff. Read matrix for LutAtoB and LutBtoA + +static +cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset) +{ + cmsFloat64Number dMat[3*3]; + cmsFloat64Number dOff[3]; + cmsStage* Mat; + + // Go to address + if (!io -> Seek(io, Offset)) return NULL; + + // Read the Matrix + if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL; + + if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL; + if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL; + + Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff); + + return Mat; +} + + + + +// V4 stuff. Read CLUT part for LutAtoB and LutBtoA + +static +cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, + cmsUInt32Number Offset, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels) +{ + cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension. + cmsUInt32Number GridPoints[cmsMAXCHANNELS], i; + cmsUInt8Number Precision; + cmsStage* CLUT; + _cmsStageCLutData* Data; + + if (!io -> Seek(io, Offset)) return NULL; + if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL; + + + for (i=0; i < cmsMAXCHANNELS; i++) { + + if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least + GridPoints[i] = gridPoints8[i]; + } + + if (!_cmsReadUInt8Number(io, &Precision)) return NULL; + + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + + CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL); + if (CLUT == NULL) return NULL; + + Data = (_cmsStageCLutData*) CLUT ->Data; + + // Precision can be 1 or 2 bytes + if (Precision == 1) { + + cmsUInt8Number v; + + for (i=0; i < Data ->nEntries; i++) { + + if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) { + cmsStageFree(CLUT); + return NULL; + } + Data ->Tab.T[i] = FROM_8_TO_16(v); + } + + } + else + if (Precision == 2) { + + if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) { + cmsStageFree(CLUT); + return NULL; + } + } + else { + cmsStageFree(CLUT); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); + return NULL; + } + + return CLUT; +} + +static +cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) +{ + cmsTagTypeSignature BaseType; + cmsUInt32Number nItems; + + BaseType = _cmsReadTypeBase(io); + switch (BaseType) { + + case cmsSigCurveType: + return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0); + + case cmsSigParametricCurveType: + return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0); + + default: + { + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) BaseType); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); + } + return NULL; + } +} + + +// Read a set of curves from specific offset +static +cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves) +{ + cmsToneCurve* Curves[cmsMAXCHANNELS]; + cmsUInt32Number i; + cmsStage* Lin = NULL; + + if (nCurves > cmsMAXCHANNELS) return FALSE; + + if (!io -> Seek(io, Offset)) return FALSE; + + for (i=0; i < nCurves; i++) + Curves[i] = NULL; + + for (i=0; i < nCurves; i++) { + + Curves[i] = ReadEmbeddedCurve(self, io); + if (Curves[i] == NULL) goto Error; + if (!_cmsReadAlignment(io)) goto Error; + + } + + Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves); + +Error: + for (i=0; i < nCurves; i++) + cmsFreeToneCurve(Curves[i]); + + return Lin; +} + + +// LutAtoB type + +// This structure represents a colour transform. The type contains up to five processing +// elements which are stored in the AtoBTag tag in the following order: a set of one +// dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves, +// a multidimensional lookup table, and a set of one dimensional output curves. +// Data are processed using these elements via the following sequence: +// +//("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves). +// +/* +It is possible to use any or all of these processing elements. At least one processing element +must be included.Only the following combinations are allowed: + +B +M - Matrix - B +A - CLUT - B +A - CLUT - M - Matrix - B + +*/ + +static +void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number BaseOffset; + cmsUInt8Number inputChan; // Number of input channels + cmsUInt8Number outputChan; // Number of output channels + cmsUInt32Number offsetB; // Offset to first "B" curve + cmsUInt32Number offsetMat; // Offset to matrix + cmsUInt32Number offsetM; // Offset to first "M" curve + cmsUInt32Number offsetC; // Offset to CLUT + cmsUInt32Number offsetA; // Offset to first "A" curve + cmsPipeline* NewLUT = NULL; + + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; + if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; + + if (!_cmsReadUInt16Number(io, NULL)) return NULL; + + if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; + + if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; + if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); + if (NewLUT == NULL) return NULL; + + if (offsetA!= 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan))) + goto Error; + } + + if (offsetC != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) + goto Error; + } + + if (offsetM != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan))) + goto Error; + } + + if (offsetMat != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) + goto Error; + } + + if (offsetB != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan))) + goto Error; + } + + *nItems = 1; + return NewLUT; +Error: + cmsPipelineFree(NewLUT); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +// Write a set of curves +static +cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe) +{ + cmsUInt32Number i, n; + + _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data; + + n = mpe->InputChannels * mpe->OutputChannels; + + // Write the Matrix + for (i = 0; i < n; i++) + { + if (!_cmsWrite15Fixed16Number(io, m->Double[i])) return FALSE; + } + + if (m->Offset != NULL) { + + for (i = 0; i < mpe->OutputChannels; i++) + { + if (!_cmsWrite15Fixed16Number(io, m->Offset[i])) return FALSE; + } + } + else { + for (i = 0; i < mpe->OutputChannels; i++) + { + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + } + } + + + return TRUE; + + cmsUNUSED_PARAMETER(self); +} + + +// Write a set of curves +static +cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe) +{ + cmsUInt32Number i, n; + cmsTagTypeSignature CurrentType; + cmsToneCurve** Curves; + + + n = cmsStageOutputChannels(mpe); + Curves = _cmsStageGetPtrToCurveSet(mpe); + + for (i=0; i < n; i++) { + + // If this is a table-based curve, use curve type even on V4 + CurrentType = Type; + + if ((Curves[i] ->nSegments == 0)|| + ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) ) + CurrentType = cmsSigCurveType; + else + if (Curves[i] ->Segments[0].Type < 0) + CurrentType = cmsSigCurveType; + + if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE; + + switch (CurrentType) { + + case cmsSigCurveType: + if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE; + break; + + case cmsSigParametricCurveType: + if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE; + break; + + default: + { + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) Type); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); + } + return FALSE; + } + + if (!_cmsWriteAlignment(io)) return FALSE; + } + + + return TRUE; +} + + +static +cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe) +{ + cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension. + cmsUInt32Number i; + _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data; + + if (CLUT ->HasFloatValues) { + cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only"); + return FALSE; + } + + memset(gridPoints, 0, sizeof(gridPoints)); + for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++) + gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i]; + + if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE; + + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; + if (!_cmsWriteUInt8Number(io, 0)) return FALSE; + + // Precision can be 1 or 2 bytes + if (Precision == 1) { + + for (i=0; i < CLUT->nEntries; i++) { + + if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE; + } + } + else + if (Precision == 2) { + + if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE; + } + else { + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); + return FALSE; + } + + if (!_cmsWriteAlignment(io)) return FALSE; + + return TRUE; +} + + + + +static +cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsPipeline* Lut = (cmsPipeline*) Ptr; + cmsUInt32Number inputChan, outputChan; + cmsStage *A = NULL, *B = NULL, *M = NULL; + cmsStage * Matrix = NULL; + cmsStage * CLUT = NULL; + cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; + cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; + + // Get the base for all offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (Lut ->Elements != NULL) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, + cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) { + + cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB"); + return FALSE; + } + + // Get input, output channels + inputChan = cmsPipelineInputChannels(Lut); + outputChan = cmsPipelineOutputChannels(Lut); + + // Write channel count + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + + // Keep directory to be filled latter + DirectoryPos = io ->Tell(io); + + // Write the directory + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + + if (A != NULL) { + + offsetA = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; + } + + if (CLUT != NULL) { + offsetC = io ->Tell(io) - BaseOffset; + if (!WriteCLUT(self, io, (Lut ->SaveAs8Bits ? 1U : 2U), CLUT)) return FALSE; + + } + if (M != NULL) { + + offsetM = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; + } + + if (Matrix != NULL) { + offsetMat = io ->Tell(io) - BaseOffset; + if (!WriteMatrix(self, io, Matrix)) return FALSE; + } + + if (B != NULL) { + + offsetB = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; + } + + CurrentPos = io ->Tell(io); + + if (!io ->Seek(io, DirectoryPos)) return FALSE; + + if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; + + if (!io ->Seek(io, CurrentPos)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// LutBToA type + +static +void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt8Number inputChan; // Number of input channels + cmsUInt8Number outputChan; // Number of output channels + cmsUInt32Number BaseOffset; // Actual position in file + cmsUInt32Number offsetB; // Offset to first "B" curve + cmsUInt32Number offsetMat; // Offset to matrix + cmsUInt32Number offsetM; // Offset to first "M" curve + cmsUInt32Number offsetC; // Offset to CLUT + cmsUInt32Number offsetA; // Offset to first "A" curve + cmsPipeline* NewLUT = NULL; + + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; + if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; + + if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; + if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; + + // Padding + if (!_cmsReadUInt16Number(io, NULL)) return NULL; + + if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); + if (NewLUT == NULL) return NULL; + + if (offsetB != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan))) + goto Error; + } + + if (offsetMat != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) + goto Error; + } + + if (offsetM != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan))) + goto Error; + } + + if (offsetC != 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) + goto Error; + } + + if (offsetA!= 0) { + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan))) + goto Error; + } + + *nItems = 1; + return NewLUT; +Error: + cmsPipelineFree(NewLUT); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +/* +B +B - Matrix - M +B - CLUT - A +B - Matrix - M - CLUT - A +*/ + +static +cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsPipeline* Lut = (cmsPipeline*) Ptr; + cmsUInt32Number inputChan, outputChan; + cmsStage *A = NULL, *B = NULL, *M = NULL; + cmsStage *Matrix = NULL; + cmsStage *CLUT = NULL; + cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; + cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; + + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A)) + if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) { + cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA"); + return FALSE; + } + + inputChan = cmsPipelineInputChannels(Lut); + outputChan = cmsPipelineOutputChannels(Lut); + + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + + DirectoryPos = io ->Tell(io); + + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + + if (A != NULL) { + + offsetA = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; + } + + if (CLUT != NULL) { + offsetC = io ->Tell(io) - BaseOffset; + if (!WriteCLUT(self, io, (Lut ->SaveAs8Bits ? 1U : 2U), CLUT)) return FALSE; + + } + if (M != NULL) { + + offsetM = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; + } + + if (Matrix != NULL) { + offsetMat = io ->Tell(io) - BaseOffset; + if (!WriteMatrix(self, io, Matrix)) return FALSE; + } + + if (B != NULL) { + + offsetB = io ->Tell(io) - BaseOffset; + if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; + } + + CurrentPos = io ->Tell(io); + + if (!io ->Seek(io, DirectoryPos)) return FALSE; + + if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; + if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; + + if (!io ->Seek(io, CurrentPos)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + + +static +void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + + +// ******************************************************************************** +// Type cmsSigColorantTableType +// ******************************************************************************** +/* +The purpose of this tag is to identify the colorants used in the profile by a +unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous +value. The first colorant listed is the colorant of the first device channel of +a lut tag. The second colorant listed is the colorant of the second device channel +of a lut tag, and so on. +*/ + +static +void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number i, Count; + cmsNAMEDCOLORLIST* List; + char Name[34]; + cmsUInt16Number PCS[3]; + + + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + if (Count > cmsMAXCHANNELS) { + cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count); + return NULL; + } + + List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", ""); + if (List == NULL) + return NULL; + + for (i=0; i < Count; i++) { + + if (io ->Read(io, Name, 32, 1) != 1) goto Error; + Name[32] = 0; + + if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; + + if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error; + + } + + *nItems = 1; + return List; + +Error: + *nItems = 0; + cmsFreeNamedColorList(List); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + + +// Saves a colorant table. It is using the named color structure for simplicity sake +static +cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; + cmsUInt32Number i, nColors; + + nColors = cmsNamedColorCount(NamedColorList); + + if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; + + for (i=0; i < nColors; i++) { + + char root[cmsMAX_PATH]; + cmsUInt16Number PCS[3]; + + memset(root, 0, sizeof(root)); + + if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0; + root[32] = 0; + + if (!io ->Write(io, 32, root)) return FALSE; + if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; + return (void*) cmsDupNamedColorList(nc); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + + +static +void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigNamedColor2Type +// ******************************************************************************** +// +//The namedColor2Type is a count value and array of structures that provide color +//coordinates for 7-bit ASCII color names. For each named color, a PCS and optional +//device representation of the color are given. Both representations are 16-bit values. +//The device representation corresponds to the header's 'color space of data' field. +//This representation should be consistent with the 'number of device components' +//field in the namedColor2Type. If this field is 0, device coordinates are not provided. +//The PCS representation corresponds to the header's PCS field. The PCS representation +//is always provided. Color names are fixed-length, 32-byte fields including null +//termination. In order to maintain maximum portability, it is strongly recommended +//that special characters of the 7-bit ASCII set not be used. + +static +void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + + cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use + cmsUInt32Number count; // Count of named colors + cmsUInt32Number nDeviceCoords; // Num of device coordinates + char prefix[32]; // Prefix for each color name + char suffix[32]; // Suffix for each color name + cmsNAMEDCOLORLIST* v; + cmsUInt32Number i; + + + *nItems = 0; + if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL; + if (!_cmsReadUInt32Number(io, &count)) return NULL; + if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL; + + if (io -> Read(io, prefix, 32, 1) != 1) return NULL; + if (io -> Read(io, suffix, 32, 1) != 1) return NULL; + + prefix[31] = suffix[31] = 0; + + v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix); + if (v == NULL) { + cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count); + return NULL; + } + + if (nDeviceCoords > cmsMAXCHANNELS) { + cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords); + goto Error; + } + for (i=0; i < count; i++) { + + cmsUInt16Number PCS[3]; + cmsUInt16Number Colorant[cmsMAXCHANNELS]; + char Root[33]; + + memset(Colorant, 0, sizeof(Colorant)); + if (io -> Read(io, Root, 32, 1) != 1) goto Error; + Root[32] = 0; // To prevent exploits + + if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; + if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error; + + if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error; + } + + *nItems = 1; + return (void*) v ; + +Error: + cmsFreeNamedColorList(v); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +// Saves a named color list into a named color profile +static +cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; + char prefix[33]; // Prefix for each color name + char suffix[33]; // Suffix for each color name + cmsUInt32Number i, nColors; + + nColors = cmsNamedColorCount(NamedColorList); + + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; + if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE; + + strncpy(prefix, (const char*) NamedColorList->Prefix, 32); + strncpy(suffix, (const char*) NamedColorList->Suffix, 32); + + suffix[32] = prefix[32] = 0; + + if (!io ->Write(io, 32, prefix)) return FALSE; + if (!io ->Write(io, 32, suffix)) return FALSE; + + for (i=0; i < nColors; i++) { + + cmsUInt16Number PCS[3]; + cmsUInt16Number Colorant[cmsMAXCHANNELS]; + char Root[cmsMAX_PATH]; + + if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0; + Root[32] = 0; + if (!io ->Write(io, 32 , Root)) return FALSE; + if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; + if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + +static +void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; + + return (void*) cmsDupNamedColorList(nc); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + + +static +void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigProfileSequenceDescType +// ******************************************************************************** + +// This type is an array of structures, each of which contains information from the +// header fields and tags from the original profiles which were combined to create +// the final profile. The order of the structures is the order in which the profiles +// were combined and includes a structure for the final profile. This provides a +// description of the profile sequence from source to destination, +// typically used with the DeviceLink profile. + +static +cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag) +{ + cmsTagTypeSignature BaseType; + cmsUInt32Number nItems; + + BaseType = _cmsReadTypeBase(io); + + switch (BaseType) { + + case cmsSigTextType: + if (*mlu) cmsMLUfree(*mlu); + *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag); + return (*mlu != NULL); + + case cmsSigTextDescriptionType: + if (*mlu) cmsMLUfree(*mlu); + *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag); + return (*mlu != NULL); + + /* + TBD: Size is needed for MLU, and we have no idea on which is the available size + */ + + case cmsSigMultiLocalizedUnicodeType: + if (*mlu) cmsMLUfree(*mlu); + *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag); + return (*mlu != NULL); + + default: return FALSE; + } +} + + +static +void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsSEQ* OutSeq; + cmsUInt32Number i, Count; + + *nItems = 0; + + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + + OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); + if (OutSeq == NULL) return NULL; + + OutSeq ->n = Count; + + // Get structures as well + + for (i=0; i < Count; i++) { + + cmsPSEQDESC* sec = &OutSeq -> seq[i]; + + if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; + SizeOfTag -= sizeof(cmsUInt32Number); + + if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; + SizeOfTag -= sizeof(cmsUInt32Number); + + if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error; + if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error; + SizeOfTag -= sizeof(cmsUInt64Number); + + if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; + SizeOfTag -= sizeof(cmsUInt32Number); + + if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error; + if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error; + } + + *nItems = 1; + return OutSeq; + +Error: + cmsFreeProfileSequenceDescription(OutSeq); + return NULL; +} + + +// Aux--Embed a text description type. It can be of type text description or multilocalized unicode +// and it depends of the version number passed on cmsTagDescriptor structure instead of stack +static +cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text) +{ + if (self ->ICCVersion < 0x4000000) { + + if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE; + return Type_Text_Description_Write(self, io, Text, 1); + } + else { + if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE; + return Type_MLU_Write(self, io, Text, 1); + } +} + + +static +cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsSEQ* Seq = (cmsSEQ*) Ptr; + cmsUInt32Number i; + + if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE; + + for (i=0; i < Seq ->n; i++) { + + cmsPSEQDESC* sec = &Seq -> seq[i]; + + if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE; + if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE; + if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE; + if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE; + + if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE; + if (!SaveDescription(self, io, sec ->Model)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigProfileSequenceIdType +// ******************************************************************************** +/* +In certain workflows using ICC Device Link Profiles, it is necessary to identify the +original profiles that were combined to create the Device Link Profile. +This type is an array of structures, each of which contains information for +identification of a profile used in a sequence +*/ + + +static +cmsBool ReadSeqID(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + cmsSEQ* OutSeq = (cmsSEQ*) Cargo; + cmsPSEQDESC* seq = &OutSeq ->seq[n]; + + if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE; + if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE; + + return TRUE; +} + + + +static +void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsSEQ* OutSeq; + cmsUInt32Number Count; + cmsUInt32Number BaseOffset; + + *nItems = 0; + + // Get actual position as a basis for element offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Get table count + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + // Allocate an empty structure + OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); + if (OutSeq == NULL) return NULL; + + + // Read the position table + if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) { + + cmsFreeProfileSequenceDescription(OutSeq); + return NULL; + } + + // Success + *nItems = 1; + return OutSeq; + +} + + +static +cmsBool WriteSeqID(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + cmsSEQ* Seq = (cmsSEQ*) Cargo; + + if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE; + + // Store here the MLU + if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsSEQ* Seq = (cmsSEQ*) Ptr; + cmsUInt32Number BaseOffset; + + // Keep the base offset + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // This is the table count + if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE; + + // This is the position table and content + if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigUcrBgType +// ******************************************************************************** +/* +This type contains curves representing the under color removal and black +generation and a text string which is a general description of the method used +for the ucr/bg. +*/ + +static +void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); + cmsUInt32Number CountUcr, CountBg; + char* ASCIIString; + + *nItems = 0; + if (n == NULL) return NULL; + + // First curve is Under color removal + if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL); + if (n ->Ucr == NULL) return NULL; + + if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= CountUcr * sizeof(cmsUInt16Number); + + // Second curve is Black generation + if (!_cmsReadUInt32Number(io, &CountBg)) return NULL; + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL); + if (n ->Bg == NULL) return NULL; + if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL; + if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL; + SizeOfTag -= CountBg * sizeof(cmsUInt16Number); + if (SizeOfTag == UINT_MAX) return NULL; + + // Now comes the text. The length is specified by the tag size + n ->Desc = cmsMLUalloc(self ->ContextID, 1); + if (n ->Desc == NULL) return NULL; + + ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); + if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL; + ASCIIString[SizeOfTag] = 0; + cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString); + _cmsFree(self ->ContextID, ASCIIString); + + *nItems = 1; + return (void*) n; +} + +static +cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUcrBg* Value = (cmsUcrBg*) Ptr; + cmsUInt32Number TextSize; + char* Text; + + // First curve is Under color removal + if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE; + if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE; + + // Then black generation + if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE; + if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE; + + // Now comes the text. The length is specified by the tag size + TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0); + Text = (char*) _cmsMalloc(self ->ContextID, TextSize); + if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE; + + if (!io ->Write(io, TextSize, Text)) return FALSE; + _cmsFree(self ->ContextID, Text); + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + cmsUcrBg* Src = (cmsUcrBg*) Ptr; + cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); + + if (NewUcrBg == NULL) return NULL; + + NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg); + NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr); + NewUcrBg ->Desc = cmsMLUdup(Src ->Desc); + + return (void*) NewUcrBg; + + cmsUNUSED_PARAMETER(n); +} + +static +void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr) +{ + cmsUcrBg* Src = (cmsUcrBg*) Ptr; + + if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr); + if (Src ->Bg) cmsFreeToneCurve(Src ->Bg); + if (Src ->Desc) cmsMLUfree(Src ->Desc); + + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigCrdInfoType +// ******************************************************************************** + +/* +This type contains the PostScript product name to which this profile corresponds +and the names of the companion CRDs. Recall that a single profile can generate +multiple CRDs. It is implemented as a MLU being the language code "PS" and then +country varies for each element: + + nm: PostScript product name + #0: Rendering intent 0 CRD name + #1: Rendering intent 1 CRD name + #2: Rendering intent 2 CRD name + #3: Rendering intent 3 CRD name +*/ + + + +// Auxiliary, read an string specified as count + string +static +cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section) +{ + cmsUInt32Number Count; + char* Text; + + if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE; + + if (!_cmsReadUInt32Number(io, &Count)) return FALSE; + + if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE; + if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE; + + Text = (char*) _cmsMalloc(self ->ContextID, Count+1); + if (Text == NULL) return FALSE; + + if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) { + _cmsFree(self ->ContextID, Text); + return FALSE; + } + + Text[Count] = 0; + + cmsMLUsetASCII(mlu, "PS", Section, Text); + _cmsFree(self ->ContextID, Text); + + *SizeOfTag -= (Count + sizeof(cmsUInt32Number)); + return TRUE; +} + +static +cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section) +{ + cmsUInt32Number TextSize; + char* Text; + + TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0); + Text = (char*) _cmsMalloc(self ->ContextID, TextSize); + + if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE; + + if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE; + + if (!io ->Write(io, TextSize, Text)) return FALSE; + _cmsFree(self ->ContextID, Text); + + return TRUE; +} + +static +void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5); + + *nItems = 0; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error; + if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error; + + *nItems = 1; + return (void*) mlu; + +Error: + cmsMLUfree(mlu); + return NULL; + +} + +static +cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + + cmsMLU* mlu = (cmsMLU*) Ptr; + + if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error; + if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error; + if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error; + if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error; + if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error; + + return TRUE; + +Error: + return FALSE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsMLUdup((cmsMLU*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr) +{ + cmsMLUfree((cmsMLU*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + +// ******************************************************************************** +// Type cmsSigScreeningType +// ******************************************************************************** +// +//The screeningType describes various screening parameters including screen +//frequency, screening angle, and spot shape. + +static +void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsScreening* sc = NULL; + cmsUInt32Number i; + + sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening)); + if (sc == NULL) return NULL; + + *nItems = 0; + + if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error; + if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error; + + if (sc ->nChannels > cmsMAXCHANNELS - 1) + sc ->nChannels = cmsMAXCHANNELS - 1; + + for (i=0; i < sc ->nChannels; i++) { + + if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error; + if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error; + if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error; + } + + + *nItems = 1; + + return (void*) sc; + +Error: + if (sc != NULL) + _cmsFree(self ->ContextID, sc); + + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsScreening* sc = (cmsScreening* ) Ptr; + cmsUInt32Number i; + + if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE; + if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE; + + for (i=0; i < sc ->nChannels; i++) { + + if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE; + if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); + + cmsUNUSED_PARAMETER(n); +} + + +static +void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + +// ******************************************************************************** +// Type cmsSigViewingConditionsType +// ******************************************************************************** +// +//This type represents a set of viewing condition parameters including: +//CIE 'absolute' illuminant white point tristimulus values and CIE 'absolute' +//surround tristimulus values. + +static +void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsICCViewingConditions* vc = NULL; + + vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions)); + if (vc == NULL) return NULL; + + *nItems = 0; + + if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error; + if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error; + if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error; + + *nItems = 1; + + return (void*) vc; + +Error: + if (vc != NULL) + _cmsFree(self ->ContextID, vc); + + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +static +cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr; + + if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE; + if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE; + if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + +static +void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsICCViewingConditions)); + + cmsUNUSED_PARAMETER(n); +} + + +static +void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigMultiProcessElementType +// ******************************************************************************** + + +static +void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsStageDup((cmsStage*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) +{ + cmsStageFree((cmsStage*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + +// Each curve is stored in one or more curve segments, with break-points specified between curve segments. +// The first curve segment always starts at -Infinity, and the last curve segment always ends at +Infinity. The +// first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be +// specified either in terms of a formula, or by a sampled curve. + + +// Read an embedded segmented curve +static +cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) +{ + cmsCurveSegSignature ElementSig; + cmsUInt32Number i, j; + cmsUInt16Number nSegments; + cmsCurveSegment* Segments; + cmsToneCurve* Curve; + cmsFloat32Number PrevBreak = MINUS_INF; // - infinite + + // Take signature and channels for each element. + if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL; + + // That should be a segmented curve + if (ElementSig != cmsSigSegmentedCurve) return NULL; + + if (!_cmsReadUInt32Number(io, NULL)) return NULL; + if (!_cmsReadUInt16Number(io, &nSegments)) return NULL; + if (!_cmsReadUInt16Number(io, NULL)) return NULL; + + if (nSegments < 1) return NULL; + Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment)); + if (Segments == NULL) return NULL; + + // Read breakpoints + for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) { + + Segments[i].x0 = PrevBreak; + if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error; + PrevBreak = Segments[i].x1; + } + + Segments[nSegments-1].x0 = PrevBreak; + Segments[nSegments-1].x1 = PLUS_INF; // A big cmsFloat32Number number + + // Read segments + for (i=0; i < nSegments; i++) { + + if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error; + if (!_cmsReadUInt32Number(io, NULL)) goto Error; + + switch (ElementSig) { + + case cmsSigFormulaCurveSeg: { + + cmsUInt16Number Type; + cmsUInt32Number ParamsByType[] = {4, 5, 5 }; + + if (!_cmsReadUInt16Number(io, &Type)) goto Error; + if (!_cmsReadUInt16Number(io, NULL)) goto Error; + + Segments[i].Type = Type + 6; + if (Type > 2) goto Error; + + for (j=0; j < ParamsByType[Type]; j++) { + + cmsFloat32Number f; + if (!_cmsReadFloat32Number(io, &f)) goto Error; + Segments[i].Params[j] = f; + } + } + break; + + + case cmsSigSampledCurveSeg: { + cmsUInt32Number Count; + + if (!_cmsReadUInt32Number(io, &Count)) goto Error; + + Segments[i].nGridPoints = Count; + Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number)); + if (Segments[i].SampledPoints == NULL) goto Error; + + for (j=0; j < Count; j++) { + if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error; + } + } + break; + + default: + { + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String); + } + goto Error; + + } + } + + Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments); + + for (i=0; i < nSegments; i++) { + if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); + } + _cmsFree(self ->ContextID, Segments); + return Curve; + +Error: + if (Segments) { + for (i=0; i < nSegments; i++) { + if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); + } + _cmsFree(self ->ContextID, Segments); + } + return NULL; +} + + +static +cmsBool ReadMPECurve(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo; + + GammaTables[n] = ReadSegmentedCurve(self, io); + return (GammaTables[n] != NULL); + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsStage* mpe = NULL; + cmsUInt16Number InputChans, OutputChans; + cmsUInt32Number i, BaseOffset; + cmsToneCurve** GammaTables; + + *nItems = 0; + + // Get actual position as a basis for element offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + if (InputChans != OutputChans) return NULL; + + GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*)); + if (GammaTables == NULL) return NULL; + + if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) { + + mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables); + } + else { + mpe = NULL; + } + + for (i=0; i < InputChans; i++) { + if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]); + } + + _cmsFree(self ->ContextID, GammaTables); + *nItems = (mpe != NULL) ? 1U : 0; + return mpe; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +// Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY +static +cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g) +{ + cmsUInt32Number i, j; + cmsCurveSegment* Segments = g ->Segments; + cmsUInt32Number nSegments = g ->nSegments; + + if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error; + if (!_cmsWriteUInt16Number(io, 0)) goto Error; + + // Write the break-points + for (i=0; i < nSegments - 1; i++) { + if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error; + } + + // Write the segments + for (i=0; i < g ->nSegments; i++) { + + cmsCurveSegment* ActualSeg = Segments + i; + + if (ActualSeg -> Type == 0) { + + // This is a sampled curve + if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error; + + for (j=0; j < g ->Segments[i].nGridPoints; j++) { + if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error; + } + + } + else { + int Type; + cmsUInt32Number ParamsByType[] = { 4, 5, 5 }; + + // This is a formula-based + if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + + // We only allow 1, 2 and 3 as types + Type = ActualSeg ->Type - 6; + if (Type > 2 || Type < 0) goto Error; + + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error; + if (!_cmsWriteUInt16Number(io, 0)) goto Error; + + for (j=0; j < ParamsByType[Type]; j++) { + if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error; + } + } + + // It seems there is no need to align. Code is here, and for safety commented out + // if (!_cmsWriteAlignment(io)) goto Error; + } + + return TRUE; + +Error: + return FALSE; +} + + +static +cmsBool WriteMPECurve(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo; + + return WriteSegmentedCurve(io, Curves ->TheCurves[n]); + + cmsUNUSED_PARAMETER(SizeOfTag); + cmsUNUSED_PARAMETER(self); +} + +// Write a curve, checking first for validity +static +cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number BaseOffset; + cmsStage* mpe = (cmsStage*) Ptr; + _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data; + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Write the header. Since those are curves, input and output channels are same + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + + if (!WritePositionTable(self, io, 0, + mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE; + + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); +} + + + +// The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the +// matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array +// is organized as follows: +// array = [e11, e12, ..., e1P, e21, e22, ..., e2P, ..., eQ1, eQ2, ..., eQP, e1, e2, ..., eQ] + +static +void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsStage* mpe; + cmsUInt16Number InputChans, OutputChans; + cmsUInt32Number nElems, i; + cmsFloat64Number* Matrix; + cmsFloat64Number* Offsets; + + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + + // Input and output chans may be ANY (up to 0xffff), + // but we choose to limit to 16 channels for now + if (InputChans >= cmsMAXCHANNELS) return NULL; + if (OutputChans >= cmsMAXCHANNELS) return NULL; + + nElems = (cmsUInt32Number) InputChans * OutputChans; + + Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number)); + if (Matrix == NULL) return NULL; + + Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number)); + if (Offsets == NULL) { + + _cmsFree(self ->ContextID, Matrix); + return NULL; + } + + for (i=0; i < nElems; i++) { + + cmsFloat32Number v; + + if (!_cmsReadFloat32Number(io, &v)) { + _cmsFree(self ->ContextID, Matrix); + _cmsFree(self ->ContextID, Offsets); + return NULL; + } + Matrix[i] = v; + } + + + for (i=0; i < OutputChans; i++) { + + cmsFloat32Number v; + + if (!_cmsReadFloat32Number(io, &v)) { + _cmsFree(self ->ContextID, Matrix); + _cmsFree(self ->ContextID, Offsets); + return NULL; + } + Offsets[i] = v; + } + + + mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets); + _cmsFree(self ->ContextID, Matrix); + _cmsFree(self ->ContextID, Offsets); + + *nItems = 1; + + return mpe; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +static +cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number i, nElems; + cmsStage* mpe = (cmsStage*) Ptr; + _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data; + + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; + + nElems = mpe ->InputChannels * mpe ->OutputChannels; + + for (i=0; i < nElems; i++) { + if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE; + } + + + for (i=0; i < mpe ->OutputChannels; i++) { + + if (Matrix ->Offset == NULL) { + + if (!_cmsWriteFloat32Number(io, 0)) return FALSE; + } + else { + if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE; + } + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + + +static +void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsStage* mpe = NULL; + cmsUInt16Number InputChans, OutputChans; + cmsUInt8Number Dimensions8[16]; + cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS]; + _cmsStageCLutData* clut; + + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + if (InputChans == 0) goto Error; + if (OutputChans == 0) goto Error; + + if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) + goto Error; + + // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number + nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? (cmsUInt32Number) MAX_INPUT_DIMENSIONS : InputChans; + + for (i = 0; i < nMaxGrids; i++) { + if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least + GridPoints[i] = (cmsUInt32Number)Dimensions8[i]; + } + + // Allocate the true CLUT + mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); + if (mpe == NULL) goto Error; + + // Read and sanitize the data + clut = (_cmsStageCLutData*) mpe ->Data; + for (i=0; i < clut ->nEntries; i++) { + + if (!_cmsReadFloat32Number(io, &clut->Tab.TFloat[i])) goto Error; + } + + *nItems = 1; + return mpe; + +Error: + *nItems = 0; + if (mpe != NULL) cmsStageFree(mpe); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + +// Write a CLUT in floating point +static +cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt8Number Dimensions8[16]; // 16 because the spec says 16 and not max number of channels + cmsUInt32Number i; + cmsStage* mpe = (cmsStage*) Ptr; + _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data; + + // Check for maximum number of channels supported by lcms + if (mpe -> InputChannels > MAX_INPUT_DIMENSIONS) return FALSE; + + // Only floats are supported in MPE + if (clut ->HasFloatValues == FALSE) return FALSE; + + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; + + memset(Dimensions8, 0, sizeof(Dimensions8)); + + for (i=0; i < mpe ->InputChannels; i++) + Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i]; + + if (!io ->Write(io, 16, Dimensions8)) return FALSE; + + for (i=0; i < clut ->nEntries; i++) { + + if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(nItems); + cmsUNUSED_PARAMETER(self); +} + + + +// This is the list of built-in MPE types +static _cmsTagTypeLinkedList SupportedMPEtypes[] = { + +{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now +{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says) + +{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] }, +{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] }, +{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, +}; + +_cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL }; + +static +cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Cargo, + cmsUInt32Number n, + cmsUInt32Number SizeOfTag) +{ + cmsStageSignature ElementSig; + cmsTagTypeHandler* TypeHandler; + cmsUInt32Number nItems; + cmsPipeline *NewLUT = (cmsPipeline *) Cargo; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); + + + // Take signature and channels for each element. + if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; + + // The reserved placeholder + if (!_cmsReadUInt32Number(io, NULL)) return FALSE; + + // Read diverse MPE types + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes); + if (TypeHandler == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); + + // An unknown element was found. + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String); + return FALSE; + } + + // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType) + // Read the MPE. No size is given + if (TypeHandler ->ReadPtr != NULL) { + + // This is a real element which should be read and processed + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag))) + return FALSE; + } + + return TRUE; + + cmsUNUSED_PARAMETER(SizeOfTag); + cmsUNUSED_PARAMETER(n); +} + + +// This is the main dispatcher for MPE +static +void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsUInt16Number InputChans, OutputChans; + cmsUInt32Number ElementCount; + cmsPipeline *NewLUT = NULL; + cmsUInt32Number BaseOffset; + + // Get actual position as a basis for element offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Read channels and element count + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL; + if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); + if (NewLUT == NULL) return NULL; + + if (!_cmsReadUInt32Number(io, &ElementCount)) goto Error; + if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) goto Error; + + // Check channel count + if (InputChans != NewLUT->InputChannels || + OutputChans != NewLUT->OutputChannels) goto Error; + + // Success + *nItems = 1; + return NewLUT; + + // Error +Error: + if (NewLUT != NULL) cmsPipelineFree(NewLUT); + *nItems = 0; + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + + +// This one is a liitle bit more complex, so we don't use position tables this time. +static +cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos; + cmsUInt32Number inputChan, outputChan; + cmsUInt32Number ElemCount; + cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before; + cmsStageSignature ElementSig; + cmsPipeline* Lut = (cmsPipeline*) Ptr; + cmsStage* Elem = Lut ->Elements; + cmsTagTypeHandler* TypeHandler; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + inputChan = cmsPipelineInputChannels(Lut); + outputChan = cmsPipelineOutputChannels(Lut); + ElemCount = cmsPipelineStageCount(Lut); + + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); + if (ElementOffsets == NULL) goto Error; + + ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); + if (ElementSizes == NULL) goto Error; + + // Write the head + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error; + if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error; + if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error; + + DirectoryPos = io ->Tell(io); + + // Write a fake directory to be filled latter on + for (i=0; i < ElemCount; i++) { + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset + if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size + } + + // Write each single tag. Keep track of the size as well. + for (i=0; i < ElemCount; i++) { + + ElementOffsets[i] = io ->Tell(io) - BaseOffset; + + ElementSig = Elem ->Type; + + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes); + if (TypeHandler == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); + + // An unknown element was found. + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String); + goto Error; + } + + if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error; + if (!_cmsWriteUInt32Number(io, 0)) goto Error; + Before = io ->Tell(io); + if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error; + if (!_cmsWriteAlignment(io)) goto Error; + + ElementSizes[i] = io ->Tell(io) - Before; + + Elem = Elem ->Next; + } + + // Write the directory + CurrentPos = io ->Tell(io); + + if (!io ->Seek(io, DirectoryPos)) goto Error; + + for (i=0; i < ElemCount; i++) { + if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; + if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; + } + + if (!io ->Seek(io, CurrentPos)) goto Error; + + if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); + return TRUE; + +Error: + if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); + if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); + return FALSE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsPipelineDup((cmsPipeline*) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + +static +void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr) +{ + cmsPipelineFree((cmsPipeline*) Ptr); + return; + + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type cmsSigVcgtType +// ******************************************************************************** + + +#define cmsVideoCardGammaTableType 0 +#define cmsVideoCardGammaFormulaType 1 + +// Used internally +typedef struct { + double Gamma; + double Min; + double Max; +} _cmsVCGTGAMMA; + + +static +void *Type_vcgt_Read(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number* nItems, + cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number TagType, n, i; + cmsToneCurve** Curves; + + *nItems = 0; + + // Read tag type + if (!_cmsReadUInt32Number(io, &TagType)) return NULL; + + // Allocate space for the array + Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); + if (Curves == NULL) return NULL; + + // There are two possible flavors + switch (TagType) { + + // Gamma is stored as a table + case cmsVideoCardGammaTableType: + { + cmsUInt16Number nChannels, nElems, nBytes; + + // Check channel count, which should be 3 (we don't support monochrome this time) + if (!_cmsReadUInt16Number(io, &nChannels)) goto Error; + + if (nChannels != 3) { + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels); + goto Error; + } + + // Get Table element count and bytes per element + if (!_cmsReadUInt16Number(io, &nElems)) goto Error; + if (!_cmsReadUInt16Number(io, &nBytes)) goto Error; + + // Adobe's quirk fixup. Fixing broken profiles... + if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576) + nBytes = 2; + + + // Populate tone curves + for (n=0; n < 3; n++) { + + Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL); + if (Curves[n] == NULL) goto Error; + + // On depending on byte depth + switch (nBytes) { + + // One byte, 0..255 + case 1: + for (i=0; i < nElems; i++) { + + cmsUInt8Number v; + + if (!_cmsReadUInt8Number(io, &v)) goto Error; + Curves[n] ->Table16[i] = FROM_8_TO_16(v); + } + break; + + // One word 0..65535 + case 2: + if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error; + break; + + // Unsupported + default: + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8); + goto Error; + } + } // For all 3 channels + } + break; + + // In this case, gamma is stored as a formula + case cmsVideoCardGammaFormulaType: + { + _cmsVCGTGAMMA Colorant[3]; + + // Populate tone curves + for (n=0; n < 3; n++) { + + double Params[10]; + + if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error; + if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error; + if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error; + + // Parametric curve type 5 is: + // Y = (aX + b)^Gamma + e | X >= d + // Y = cX + f | X < d + + // vcgt formula is: + // Y = (Max - Min) * (X ^ Gamma) + Min + + // So, the translation is + // a = (Max - Min) ^ ( 1 / Gamma) + // e = Min + // b=c=d=f=0 + + Params[0] = Colorant[n].Gamma; + Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma)); + Params[2] = 0; + Params[3] = 0; + Params[4] = 0; + Params[5] = Colorant[n].Min; + Params[6] = 0; + + Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params); + if (Curves[n] == NULL) goto Error; + } + } + break; + + // Unsupported + default: + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType); + goto Error; + } + + *nItems = 1; + return (void*) Curves; + +// Regret, free all resources +Error: + + cmsFreeToneCurveTriple(Curves); + _cmsFree(self ->ContextID, Curves); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + +// We don't support all flavors, only 16bits tables and formula +static +cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsToneCurve** Curves = (cmsToneCurve**) Ptr; + cmsUInt32Number i, j; + + if (cmsGetToneCurveParametricType(Curves[0]) == 5 && + cmsGetToneCurveParametricType(Curves[1]) == 5 && + cmsGetToneCurveParametricType(Curves[2]) == 5) { + + if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; + + // Save parameters + for (i=0; i < 3; i++) { + + _cmsVCGTGAMMA v; + + v.Gamma = Curves[i] ->Segments[0].Params[0]; + v.Min = Curves[i] ->Segments[0].Params[5]; + v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min; + + if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE; + } + } + + else { + + // Always store as a table of 256 words + if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE; + if (!_cmsWriteUInt16Number(io, 3)) return FALSE; + if (!_cmsWriteUInt16Number(io, 256)) return FALSE; + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; + + for (i=0; i < 3; i++) { + for (j=0; j < 256; j++) { + + cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0)); + cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0); + + if (!_cmsWriteUInt16Number(io, n)) return FALSE; + } + } + } + + return TRUE; + + cmsUNUSED_PARAMETER(self); + cmsUNUSED_PARAMETER(nItems); +} + +static +void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr; + cmsToneCurve** NewCurves; + + NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); + if (NewCurves == NULL) return NULL; + + NewCurves[0] = cmsDupToneCurve(OldCurves[0]); + NewCurves[1] = cmsDupToneCurve(OldCurves[1]); + NewCurves[2] = cmsDupToneCurve(OldCurves[2]); + + return (void*) NewCurves; + + cmsUNUSED_PARAMETER(n); +} + + +static +void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsFreeToneCurveTriple((cmsToneCurve**) Ptr); + _cmsFree(self ->ContextID, Ptr); +} + + +// ******************************************************************************** +// Type cmsSigDictType +// ******************************************************************************** + +// Single column of the table can point to wchar or MLUC elements. Holds arrays of data +typedef struct { + cmsContext ContextID; + cmsUInt32Number *Offsets; + cmsUInt32Number *Sizes; +} _cmsDICelem; + +typedef struct { + _cmsDICelem Name, Value, DisplayName, DisplayValue; + +} _cmsDICarray; + +// Allocate an empty array element +static +cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count) +{ + e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); + if (e->Offsets == NULL) return FALSE; + + e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); + if (e->Sizes == NULL) { + + _cmsFree(ContextID, e -> Offsets); + return FALSE; + } + + e ->ContextID = ContextID; + return TRUE; +} + +// Free an array element +static +void FreeElem(_cmsDICelem* e) +{ + if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets); + if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes); + e->Offsets = e ->Sizes = NULL; +} + +// Get rid of whole array +static +void FreeArray( _cmsDICarray* a) +{ + if (a ->Name.Offsets != NULL) FreeElem(&a->Name); + if (a ->Value.Offsets != NULL) FreeElem(&a ->Value); + if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName); + if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue); +} + + +// Allocate whole array +static +cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) +{ + // Empty values + memset(a, 0, sizeof(_cmsDICarray)); + + // On depending on record size, create column arrays + if (!AllocElem(ContextID, &a ->Name, Count)) goto Error; + if (!AllocElem(ContextID, &a ->Value, Count)) goto Error; + + if (Length > 16) { + if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error; + + } + if (Length > 24) { + if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error; + } + return TRUE; + +Error: + FreeArray(a); + return FALSE; +} + +// Read one element +static +cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset) +{ + if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE; + if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE; + + // An offset of zero has special meaning and shal be preserved + if (e ->Offsets[i] > 0) + e ->Offsets[i] += BaseOffset; + return TRUE; +} + + +static +cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset) +{ + cmsUInt32Number i; + + // Read column arrays + for (i=0; i < Count; i++) { + + if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE; + if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE; + + if (Length > 16) { + + if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE; + + } + + if (Length > 24) { + + if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE; + } + } + return TRUE; +} + + +// Write one element +static +cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i) +{ + if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE; + if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE; + + return TRUE; +} + +static +cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) +{ + cmsUInt32Number i; + + for (i=0; i < Count; i++) { + + if (!WriteOneElem(io, &a -> Name, i)) return FALSE; + if (!WriteOneElem(io, &a -> Value, i)) return FALSE; + + if (Length > 16) { + + if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE; + } + + if (Length > 24) { + + if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE; + } + } + + return TRUE; +} + +static +cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr) +{ + + cmsUInt32Number nChars; + + // Special case for undefined strings (see ICC Votable + // Proposal Submission, Dictionary Type and Metadata TAG Definition) + if (e -> Offsets[i] == 0) { + + *wcstr = NULL; + return TRUE; + } + + if (!io -> Seek(io, e -> Offsets[i])) return FALSE; + + nChars = e ->Sizes[i] / sizeof(cmsUInt16Number); + + + *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t)); + if (*wcstr == NULL) return FALSE; + + if (!_cmsReadWCharArray(io, nChars, *wcstr)) { + _cmsFree(e ->ContextID, *wcstr); + return FALSE; + } + + // End of string marker + (*wcstr)[nChars] = 0; + return TRUE; +} + +static +cmsUInt32Number mywcslen(const wchar_t *s) +{ + const wchar_t *p; + + p = s; + while (*p) + p++; + + return (cmsUInt32Number)(p - s); +} + +static +cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset) +{ + cmsUInt32Number Before = io ->Tell(io); + cmsUInt32Number n; + + e ->Offsets[i] = Before - BaseOffset; + + if (wcstr == NULL) { + e ->Sizes[i] = 0; + e ->Offsets[i] = 0; + return TRUE; + } + + n = mywcslen(wcstr); + if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE; + + e ->Sizes[i] = io ->Tell(io) - Before; + return TRUE; +} + +static +cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu) +{ + cmsUInt32Number nItems = 0; + + // A way to get null MLUCs + if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) { + + *mlu = NULL; + return TRUE; + } + + if (!io -> Seek(io, e -> Offsets[i])) return FALSE; + + *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]); + return *mlu != NULL; +} + +static +cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset) +{ + cmsUInt32Number Before; + + // Special case for undefined strings (see ICC Votable + // Proposal Submission, Dictionary Type and Metadata TAG Definition) + if (mlu == NULL) { + e ->Sizes[i] = 0; + e ->Offsets[i] = 0; + return TRUE; + } + + Before = io ->Tell(io); + e ->Offsets[i] = Before - BaseOffset; + + if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE; + + e ->Sizes[i] = io ->Tell(io) - Before; + return TRUE; +} + + +static +void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsHANDLE hDict; + cmsUInt32Number i, Count, Length; + cmsUInt32Number BaseOffset; + _cmsDICarray a; + wchar_t *NameWCS = NULL, *ValueWCS = NULL; + cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL; + cmsBool rc; + + *nItems = 0; + + // Get actual position as a basis for element offsets + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Get name-value record count + if (!_cmsReadUInt32Number(io, &Count)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + // Get rec length + if (!_cmsReadUInt32Number(io, &Length)) return NULL; + SizeOfTag -= sizeof(cmsUInt32Number); + + // Check for valid lengths + if (Length != 16 && Length != 24 && Length != 32) { + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length); + return NULL; + } + + // Creates an empty dictionary + hDict = cmsDictAlloc(self -> ContextID); + if (hDict == NULL) return NULL; + + // On depending on record size, create column arrays + if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error; + + // Read column arrays + if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error; + + // Seek to each element and read it + for (i=0; i < Count; i++) { + + if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error; + if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error; + + if (Length > 16) { + if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error; + } + + if (Length > 24) { + if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error; + } + + if (NameWCS == NULL || ValueWCS == NULL) { + + cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value"); + rc = FALSE; + } + else { + + rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); + } + + if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS); + if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS); + if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU); + if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU); + + if (!rc) goto Error; + } + + FreeArray(&a); + *nItems = 1; + return (void*) hDict; + +Error: + FreeArray(&a); + cmsDictFree(hDict); + return NULL; +} + + +static +cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsHANDLE hDict = (cmsHANDLE) Ptr; + const cmsDICTentry* p; + cmsBool AnyName, AnyValue; + cmsUInt32Number i, Count, Length; + cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset; + _cmsDICarray a; + + if (hDict == NULL) return FALSE; + + BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); + + // Let's inspect the dictionary + Count = 0; AnyName = FALSE; AnyValue = FALSE; + for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) { + + if (p ->DisplayName != NULL) AnyName = TRUE; + if (p ->DisplayValue != NULL) AnyValue = TRUE; + Count++; + } + + Length = 16; + if (AnyName) Length += 8; + if (AnyValue) Length += 8; + + if (!_cmsWriteUInt32Number(io, Count)) return FALSE; + if (!_cmsWriteUInt32Number(io, Length)) return FALSE; + + // Keep starting position of offsets table + DirectoryPos = io ->Tell(io); + + // Allocate offsets array + if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error; + + // Write a fake directory to be filled latter on + if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; + + // Write each element. Keep track of the size as well. + p = cmsDictGetEntryList(hDict); + for (i=0; i < Count; i++) { + + if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error; + if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error; + + if (p ->DisplayName != NULL) { + if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error; + } + + if (p ->DisplayValue != NULL) { + if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error; + } + + p = cmsDictNextEntry(p); + } + + // Write the directory + CurrentPos = io ->Tell(io); + if (!io ->Seek(io, DirectoryPos)) goto Error; + + if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; + + if (!io ->Seek(io, CurrentPos)) goto Error; + + FreeArray(&a); + return TRUE; + +Error: + FreeArray(&a); + return FALSE; + + cmsUNUSED_PARAMETER(nItems); +} + + +static +void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) +{ + return (void*) cmsDictDup((cmsHANDLE) Ptr); + + cmsUNUSED_PARAMETER(n); + cmsUNUSED_PARAMETER(self); +} + + +static +void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsDictFree((cmsHANDLE) Ptr); + cmsUNUSED_PARAMETER(self); +} + + +// ******************************************************************************** +// Type support main routines +// ******************************************************************************** + + +// This is the list of built-in types +static const _cmsTagTypeLinkedList SupportedTagTypes[] = { + +{TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), (_cmsTagTypeLinkedList*) &SupportedTagTypes[1] }, +{TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), (_cmsTagTypeLinkedList*) &SupportedTagTypes[2] }, +{TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[3] }, +{TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[4] }, +{TYPE_HANDLER(cmsSigTextType, Text), (_cmsTagTypeLinkedList*) &SupportedTagTypes[5] }, +{TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), (_cmsTagTypeLinkedList*) &SupportedTagTypes[6] }, +{TYPE_HANDLER(cmsSigCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[7] }, +{TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[8] }, +{TYPE_HANDLER(cmsSigDateTimeType, DateTime), (_cmsTagTypeLinkedList*) &SupportedTagTypes[9] }, +{TYPE_HANDLER(cmsSigLut8Type, LUT8), (_cmsTagTypeLinkedList*) &SupportedTagTypes[10] }, +{TYPE_HANDLER(cmsSigLut16Type, LUT16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[11] }, +{TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), (_cmsTagTypeLinkedList*) &SupportedTagTypes[12] }, +{TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), (_cmsTagTypeLinkedList*) &SupportedTagTypes[13] }, +{TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), (_cmsTagTypeLinkedList*) &SupportedTagTypes[14] }, +{TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc),(_cmsTagTypeLinkedList*) &SupportedTagTypes[15] }, +{TYPE_HANDLER(cmsSigSignatureType, Signature), (_cmsTagTypeLinkedList*) &SupportedTagTypes[16] }, +{TYPE_HANDLER(cmsSigMeasurementType, Measurement), (_cmsTagTypeLinkedList*) &SupportedTagTypes[17] }, +{TYPE_HANDLER(cmsSigDataType, Data), (_cmsTagTypeLinkedList*) &SupportedTagTypes[18] }, +{TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), (_cmsTagTypeLinkedList*) &SupportedTagTypes[19] }, +{TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), (_cmsTagTypeLinkedList*) &SupportedTagTypes[20] }, +{TYPE_HANDLER(cmsSigUcrBgType, UcrBg), (_cmsTagTypeLinkedList*) &SupportedTagTypes[21] }, +{TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), (_cmsTagTypeLinkedList*) &SupportedTagTypes[22] }, +{TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), (_cmsTagTypeLinkedList*) &SupportedTagTypes[23] }, +{TYPE_HANDLER(cmsSigScreeningType, Screening), (_cmsTagTypeLinkedList*) &SupportedTagTypes[24] }, +{TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), (_cmsTagTypeLinkedList*) &SupportedTagTypes[25] }, +{TYPE_HANDLER(cmsSigXYZType, XYZ), (_cmsTagTypeLinkedList*) &SupportedTagTypes[26] }, +{TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), (_cmsTagTypeLinkedList*) &SupportedTagTypes[27] }, +{TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[28] }, +{TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), (_cmsTagTypeLinkedList*) &SupportedTagTypes[29] }, +{TYPE_HANDLER(cmsSigDictType, Dictionary), (_cmsTagTypeLinkedList*) &SupportedTagTypes[30] }, +{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } +}; + + +_cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL }; + + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagTypeList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src, + int loc) +{ + _cmsTagTypePluginChunkType newHead = { NULL }; + _cmsTagTypeLinkedList* entry; + _cmsTagTypeLinkedList* Anterior = NULL; + _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc]; + + // Walk the list copying all nodes + for (entry = head->TagTypes; + entry != NULL; + entry = entry ->Next) { + + _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TagTypes == NULL) + newHead.TagTypes = newEntry; + } + + ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType)); +} + + +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, TagTypePlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } +} + +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, MPEPlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } + +} + + +// Both kind of plug-ins share same structure +cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) +{ + return RegisterTypesPlugin(id, Data, TagTypePlugin); +} + +cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) +{ + return RegisterTypesPlugin(id, Data,MPEPlugin); +} + + +// Wrapper for tag types +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig) +{ + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin); + + return GetHandler(sig, ctx->TagTypes, (_cmsTagTypeLinkedList*) SupportedTagTypes); +} + +// ******************************************************************************** +// Tag support main routines +// ******************************************************************************** + +typedef struct _cmsTagLinkedList_st { + + cmsTagSignature Signature; + cmsTagDescriptor Descriptor; + struct _cmsTagLinkedList_st* Next; + +} _cmsTagLinkedList; + +// This is the list of built-in tags. The data of this list can be modified by plug-ins +static _cmsTagLinkedList SupportedTags[] = { + + { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]}, + { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]}, + { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]}, + { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]}, + { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]}, + { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]}, + + // Allow corbis and its broken XYZ type + { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]}, + { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]}, + { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]}, + + { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]}, + { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]}, + { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]}, + + { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]}, + { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]}, + + { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]}, + { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]}, + { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]}, + { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]}, + { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]}, + + { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]}, + { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]}, + + { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]}, + { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]}, + + { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]}, + + { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]}, + { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]}, + + { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]}, + { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]}, + + { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]}, + + { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]}, + { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]}, + { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]}, + + { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]}, + { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]}, + { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]}, + + { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]}, + { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]}, + { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]}, + + { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]}, + + { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]}, + { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]}, + { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]}, + { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]}, + { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]}, + { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]}, + + { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]}, + + { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]}, + { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]}, + + { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]}, + { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]}, + { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]}, + { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]}, + { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]}, + { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]}, + { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]}, + { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]}, + + { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]}, + { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]}, + + { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, + { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, + { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]}, + { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]}, + + { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]}, + { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL} + +}; + +/* + Not supported Why + ======================= ========================================= + cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT! + cmsSigNamedColorTag ==> Deprecated + cmsSigDataTag ==> Ancient, unused + cmsSigDeviceSettingsTag ==> Deprecated, useless +*/ + + +_cmsTagPluginChunkType _cmsTagPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTagPluginChunkType newHead = { NULL }; + _cmsTagLinkedList* entry; + _cmsTagLinkedList* Anterior = NULL; + _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin]; + + // Walk the list copying all nodes + for (entry = head->Tag; + entry != NULL; + entry = entry ->Next) { + + _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Tag == NULL) + newHead.Tag = newEntry; + } + + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType)); +} + +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + DupTagList(ctx, src); + } + else { + static _cmsTagPluginChunkType TagPluginChunk = { NULL }; + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType)); + } + +} + +cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) +{ + cmsPluginTag* Plugin = (cmsPluginTag*) Data; + _cmsTagLinkedList *pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin); + + if (Data == NULL) { + + TagPluginChunk->Tag = NULL; + return TRUE; + } + + pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); + if (pt == NULL) return FALSE; + + pt ->Signature = Plugin ->Signature; + pt ->Descriptor = Plugin ->Descriptor; + pt ->Next = TagPluginChunk ->Tag; + + TagPluginChunk ->Tag = pt; + + return TRUE; +} + +// Return a descriptor for a given tag or NULL +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig) +{ + _cmsTagLinkedList* pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin); + + for (pt = TagPluginChunk->Tag; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Signature) return &pt ->Descriptor; + } + + for (pt = SupportedTags; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Signature) return &pt ->Descriptor; + } + + return NULL; +} + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsvirt.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsvirt.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsvirt.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsvirt.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1246 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Virtual (built-in) profiles +// ----------------------------------------------------------------------------------- + +static +cmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description) +{ + cmsMLU *DescriptionMLU, *CopyrightMLU; + cmsBool rc = FALSE; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + DescriptionMLU = cmsMLUalloc(ContextID, 1); + CopyrightMLU = cmsMLUalloc(ContextID, 1); + + if (DescriptionMLU == NULL || CopyrightMLU == NULL) goto Error; + + if (!cmsMLUsetWide(DescriptionMLU, "en", "US", Description)) goto Error; + if (!cmsMLUsetWide(CopyrightMLU, "en", "US", L"No copyright, use freely")) goto Error; + + if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Error; + if (!cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU)) goto Error; + + rc = TRUE; + +Error: + + if (DescriptionMLU) + cmsMLUfree(DescriptionMLU); + if (CopyrightMLU) + cmsMLUfree(CopyrightMLU); + return rc; +} + + +static +cmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model) +{ + cmsBool rc = FALSE; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsSEQ* Seq = cmsAllocProfileSequenceDescription(ContextID, 1); + + if (Seq == NULL) return FALSE; + + Seq->seq[0].deviceMfg = (cmsSignature) 0; + Seq->seq[0].deviceModel = (cmsSignature) 0; + +#ifdef CMS_DONT_USE_INT64 + Seq->seq[0].attributes[0] = 0; + Seq->seq[0].attributes[1] = 0; +#else + Seq->seq[0].attributes = 0; +#endif + + Seq->seq[0].technology = (cmsTechnologySignature) 0; + + cmsMLUsetASCII( Seq->seq[0].Manufacturer, cmsNoLanguage, cmsNoCountry, "Little CMS"); + cmsMLUsetASCII( Seq->seq[0].Model, cmsNoLanguage, cmsNoCountry, Model); + + if (!_cmsWriteProfileSequence(hProfile, Seq)) goto Error; + + rc = TRUE; + +Error: + if (Seq) + cmsFreeProfileSequenceDescription(Seq); + + return rc; +} + + + +// This function creates a profile based on White point, primaries and +// transfer functions. +cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, + const cmsCIExyY* WhitePoint, + const cmsCIExyYTRIPLE* Primaries, + cmsToneCurve* const TransferFunction[3]) +{ + cmsHPROFILE hICC; + cmsMAT3 MColorants; + cmsCIEXYZTRIPLE Colorants; + cmsCIExyY MaxWhite; + cmsMAT3 CHAD; + cmsCIEXYZ WhitePointXYZ; + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; + + cmsSetProfileVersion(hICC, 4.3); + + cmsSetDeviceClass(hICC, cmsSigDisplayClass); + cmsSetColorSpace(hICC, cmsSigRgbData); + cmsSetPCS(hICC, cmsSigXYZData); + + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Implement profile using following tags: + // + // 1 cmsSigProfileDescriptionTag + // 2 cmsSigMediaWhitePointTag + // 3 cmsSigRedColorantTag + // 4 cmsSigGreenColorantTag + // 5 cmsSigBlueColorantTag + // 6 cmsSigRedTRCTag + // 7 cmsSigGreenTRCTag + // 8 cmsSigBlueTRCTag + // 9 Chromatic adaptation Tag + // This conforms a standard RGB DisplayProfile as says ICC, and then I add (As per addendum II) + // 10 cmsSigChromaticityTag + + + if (!SetTextTags(hICC, L"RGB built-in")) goto Error; + + if (WhitePoint) { + + if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; + + cmsxyY2XYZ(&WhitePointXYZ, WhitePoint); + _cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ()); + + // This is a V4 tag, but many CMM does read and understand it no matter which version + if (!cmsWriteTag(hICC, cmsSigChromaticAdaptationTag, (void*) &CHAD)) goto Error; + } + + if (WhitePoint && Primaries) { + + MaxWhite.x = WhitePoint -> x; + MaxWhite.y = WhitePoint -> y; + MaxWhite.Y = 1.0; + + if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error; + + Colorants.Red.X = MColorants.v[0].n[0]; + Colorants.Red.Y = MColorants.v[1].n[0]; + Colorants.Red.Z = MColorants.v[2].n[0]; + + Colorants.Green.X = MColorants.v[0].n[1]; + Colorants.Green.Y = MColorants.v[1].n[1]; + Colorants.Green.Z = MColorants.v[2].n[1]; + + Colorants.Blue.X = MColorants.v[0].n[2]; + Colorants.Blue.Y = MColorants.v[1].n[2]; + Colorants.Blue.Z = MColorants.v[2].n[2]; + + if (!cmsWriteTag(hICC, cmsSigRedColorantTag, (void*) &Colorants.Red)) goto Error; + if (!cmsWriteTag(hICC, cmsSigBlueColorantTag, (void*) &Colorants.Blue)) goto Error; + if (!cmsWriteTag(hICC, cmsSigGreenColorantTag, (void*) &Colorants.Green)) goto Error; + } + + + if (TransferFunction) { + + // Tries to minimize space. Thanks to Richard Hughes for this nice idea + if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error; + + if (TransferFunction[1] == TransferFunction[0]) { + + if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error; + + } else { + + if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error; + } + + if (TransferFunction[2] == TransferFunction[0]) { + + if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error; + + } else { + + if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; + } + } + + if (Primaries) { + if (!cmsWriteTag(hICC, cmsSigChromaticityTag, (void*) Primaries)) goto Error; + } + + + return hICC; + +Error: + if (hICC) + cmsCloseProfile(hICC); + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint, + const cmsCIExyYTRIPLE* Primaries, + cmsToneCurve* const TransferFunction[3]) +{ + return cmsCreateRGBProfileTHR(NULL, WhitePoint, Primaries, TransferFunction); +} + + + +// This function creates a profile based on White point and transfer function. +cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, + const cmsCIExyY* WhitePoint, + const cmsToneCurve* TransferFunction) +{ + cmsHPROFILE hICC; + cmsCIEXYZ tmp; + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; + + cmsSetProfileVersion(hICC, 4.3); + + cmsSetDeviceClass(hICC, cmsSigDisplayClass); + cmsSetColorSpace(hICC, cmsSigGrayData); + cmsSetPCS(hICC, cmsSigXYZData); + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Implement profile using following tags: + // + // 1 cmsSigProfileDescriptionTag + // 2 cmsSigMediaWhitePointTag + // 3 cmsSigGrayTRCTag + + // This conforms a standard Gray DisplayProfile + + // Fill-in the tags + + if (!SetTextTags(hICC, L"gray built-in")) goto Error; + + + if (WhitePoint) { + + cmsxyY2XYZ(&tmp, WhitePoint); + if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) &tmp)) goto Error; + } + + if (TransferFunction) { + + if (!cmsWriteTag(hICC, cmsSigGrayTRCTag, (void*) TransferFunction)) goto Error; + } + + return hICC; + +Error: + if (hICC) + cmsCloseProfile(hICC); + return NULL; +} + + + +cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint, + const cmsToneCurve* TransferFunction) +{ + return cmsCreateGrayProfileTHR(NULL, WhitePoint, TransferFunction); +} + +// This is a devicelink operating in the target colorspace with as many transfer functions as components + +cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, + cmsColorSpaceSignature ColorSpace, + cmsToneCurve* const TransferFunctions[]) +{ + cmsHPROFILE hICC; + cmsPipeline* Pipeline; + cmsUInt32Number nChannels; + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) + return NULL; + + cmsSetProfileVersion(hICC, 4.3); + + cmsSetDeviceClass(hICC, cmsSigLinkClass); + cmsSetColorSpace(hICC, ColorSpace); + cmsSetPCS(hICC, ColorSpace); + + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + // Set up channels + nChannels = cmsChannelsOf(ColorSpace); + + // Creates a Pipeline with prelinearization step only + Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels); + if (Pipeline == NULL) goto Error; + + + // Copy tables to Pipeline + if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions))) + goto Error; + + // Create tags + if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; + if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error; + if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error; + + // Pipeline is already on virtual profile + cmsPipelineFree(Pipeline); + + // Ok, done + return hICC; + +Error: + cmsPipelineFree(Pipeline); + if (hICC) + cmsCloseProfile(hICC); + + + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace, + cmsToneCurve* const TransferFunctions[]) +{ + return cmsCreateLinearizationDeviceLinkTHR(NULL, ColorSpace, TransferFunctions); +} + +// Ink-limiting algorithm +// +// Sum = C + M + Y + K +// If Sum > InkLimit +// Ratio= 1 - (Sum - InkLimit) / (C + M + Y) +// if Ratio <0 +// Ratio=0 +// endif +// Else +// Ratio=1 +// endif +// +// C = Ratio * C +// M = Ratio * M +// Y = Ratio * Y +// K: Does not change + +static +int InkLimitingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo) +{ + cmsFloat64Number InkLimit = *(cmsFloat64Number *) Cargo; + cmsFloat64Number SumCMY, SumCMYK, Ratio; + + InkLimit = (InkLimit * 655.35); + + SumCMY = In[0] + In[1] + In[2]; + SumCMYK = SumCMY + In[3]; + + if (SumCMYK > InkLimit) { + + Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY); + if (Ratio < 0) + Ratio = 0; + } + else Ratio = 1; + + Out[0] = _cmsQuickSaturateWord(In[0] * Ratio); // C + Out[1] = _cmsQuickSaturateWord(In[1] * Ratio); // M + Out[2] = _cmsQuickSaturateWord(In[2] * Ratio); // Y + + Out[3] = In[3]; // K (untouched) + + return TRUE; +} + +// This is a devicelink operating in CMYK for ink-limiting + +cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, + cmsColorSpaceSignature ColorSpace, + cmsFloat64Number Limit) +{ + cmsHPROFILE hICC; + cmsPipeline* LUT; + cmsStage* CLUT; + cmsUInt32Number nChannels; + + if (ColorSpace != cmsSigCmykData) { + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported"); + return NULL; + } + + if (Limit < 0.0 || Limit > 400) { + + cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); + if (Limit < 0) Limit = 0; + if (Limit > 400) Limit = 400; + + } + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; + + cmsSetProfileVersion(hICC, 4.3); + + cmsSetDeviceClass(hICC, cmsSigLinkClass); + cmsSetColorSpace(hICC, ColorSpace); + cmsSetPCS(hICC, ColorSpace); + + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + + // Creates a Pipeline with 3D grid only + LUT = cmsPipelineAlloc(ContextID, 4, 4); + if (LUT == NULL) goto Error; + + + nChannels = cmsChannelsOf(ColorSpace); + + CLUT = cmsStageAllocCLut16bit(ContextID, 17, nChannels, nChannels, NULL); + if (CLUT == NULL) goto Error; + + if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error; + + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)) || + !cmsPipelineInsertStage(LUT, cmsAT_END, CLUT) || + !cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels))) + goto Error; + + // Create tags + if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error; + + if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) LUT)) goto Error; + if (!SetSeqDescTag(hICC, "ink-limiting built-in")) goto Error; + + // cmsPipeline is already on virtual profile + cmsPipelineFree(LUT); + + // Ok, done + return hICC; + +Error: + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hICC != NULL) + cmsCloseProfile(hICC); + + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit) +{ + return cmsCreateInkLimitingDeviceLinkTHR(NULL, ColorSpace, Limit); +} + + +// Creates a fake Lab identity. +cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) +{ + cmsHPROFILE hProfile; + cmsPipeline* LUT = NULL; + + hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetProfileVersion(hProfile, 2.1); + + cmsSetDeviceClass(hProfile, cmsSigAbstractClass); + cmsSetColorSpace(hProfile, cmsSigLabData); + cmsSetPCS(hProfile, cmsSigLabData); + + if (!SetTextTags(hProfile, L"Lab identity built-in")) return NULL; + + // An identity LUT is all we need + LUT = cmsPipelineAlloc(ContextID, 3, 3); + if (LUT == NULL) goto Error; + + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3))) + goto Error; + + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; + cmsPipelineFree(LUT); + + return hProfile; + +Error: + + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hProfile != NULL) + cmsCloseProfile(hProfile); + + return NULL; +} + + +cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint) +{ + return cmsCreateLab2ProfileTHR(NULL, WhitePoint); +} + + +// Creates a fake Lab V4 identity. +cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint) +{ + cmsHPROFILE hProfile; + cmsPipeline* LUT = NULL; + + hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetProfileVersion(hProfile, 4.3); + + cmsSetDeviceClass(hProfile, cmsSigAbstractClass); + cmsSetColorSpace(hProfile, cmsSigLabData); + cmsSetPCS(hProfile, cmsSigLabData); + + if (!SetTextTags(hProfile, L"Lab identity built-in")) goto Error; + + // An empty LUTs is all we need + LUT = cmsPipelineAlloc(ContextID, 3, 3); + if (LUT == NULL) goto Error; + + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) + goto Error; + + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; + cmsPipelineFree(LUT); + + return hProfile; + +Error: + + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hProfile != NULL) + cmsCloseProfile(hProfile); + + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint) +{ + return cmsCreateLab4ProfileTHR(NULL, WhitePoint); +} + + +// Creates a fake XYZ identity +cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) +{ + cmsHPROFILE hProfile; + cmsPipeline* LUT = NULL; + + hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL); + if (hProfile == NULL) return NULL; + + cmsSetProfileVersion(hProfile, 4.3); + + cmsSetDeviceClass(hProfile, cmsSigAbstractClass); + cmsSetColorSpace(hProfile, cmsSigXYZData); + cmsSetPCS(hProfile, cmsSigXYZData); + + if (!SetTextTags(hProfile, L"XYZ identity built-in")) goto Error; + + // An identity LUT is all we need + LUT = cmsPipelineAlloc(ContextID, 3, 3); + if (LUT == NULL) goto Error; + + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) + goto Error; + + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; + cmsPipelineFree(LUT); + + return hProfile; + +Error: + + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hProfile != NULL) + cmsCloseProfile(hProfile); + + return NULL; +} + + +cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void) +{ + return cmsCreateXYZProfileTHR(NULL); +} + + +//sRGB Curves are defined by: +// +//If R'sRGB,G'sRGB, B'sRGB < 0.04045 +// +// R = R'sRGB / 12.92 +// G = G'sRGB / 12.92 +// B = B'sRGB / 12.92 +// +// +//else if R'sRGB,G'sRGB, B'sRGB >= 0.04045 +// +// R = ((R'sRGB + 0.055) / 1.055)^2.4 +// G = ((G'sRGB + 0.055) / 1.055)^2.4 +// B = ((B'sRGB + 0.055) / 1.055)^2.4 + +static +cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) +{ + cmsFloat64Number Parameters[5]; + + Parameters[0] = 2.4; + Parameters[1] = 1. / 1.055; + Parameters[2] = 0.055 / 1.055; + Parameters[3] = 1. / 12.92; + Parameters[4] = 0.04045; + + return cmsBuildParametricToneCurve(ContextID, 4, Parameters); +} + +// Create the ICC virtual profile for sRGB space +cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) +{ + cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 }; + cmsCIExyYTRIPLE Rec709Primaries = { + {0.6400, 0.3300, 1.0}, + {0.3000, 0.6000, 1.0}, + {0.1500, 0.0600, 1.0} + }; + cmsToneCurve* Gamma22[3]; + cmsHPROFILE hsRGB; + + // cmsWhitePointFromTemp(&D65, 6504); + Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); + if (Gamma22[0] == NULL) return NULL; + + hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22); + cmsFreeToneCurve(Gamma22[0]); + if (hsRGB == NULL) return NULL; + + if (!SetTextTags(hsRGB, L"sRGB built-in")) { + cmsCloseProfile(hsRGB); + return NULL; + } + + return hsRGB; +} + +cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) +{ + return cmsCreate_sRGBProfileTHR(NULL); +} + + + +typedef struct { + cmsFloat64Number Brightness; + cmsFloat64Number Contrast; + cmsFloat64Number Hue; + cmsFloat64Number Saturation; + cmsBool lAdjustWP; + cmsCIEXYZ WPsrc, WPdest; + +} BCHSWADJUSTS, *LPBCHSWADJUSTS; + + +static +int bchswSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo) +{ + cmsCIELab LabIn, LabOut; + cmsCIELCh LChIn, LChOut; + cmsCIEXYZ XYZ; + LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; + + + cmsLabEncoded2Float(&LabIn, In); + + + cmsLab2LCh(&LChIn, &LabIn); + + // Do some adjusts on LCh + + LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness; + LChOut.C = LChIn.C + bchsw -> Saturation; + LChOut.h = LChIn.h + bchsw -> Hue; + + + cmsLCh2Lab(&LabOut, &LChOut); + + // Move white point in Lab + if (bchsw->lAdjustWP) { + cmsLab2XYZ(&bchsw->WPsrc, &XYZ, &LabOut); + cmsXYZ2Lab(&bchsw->WPdest, &LabOut, &XYZ); + } + + // Back to encoded + + cmsFloat2LabEncoded(Out, &LabOut); + + return TRUE; +} + + +// Creates an abstract profile operating in Lab space for Brightness, +// contrast, Saturation and white point displacement + +cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, + cmsUInt32Number nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + cmsUInt32Number TempSrc, + cmsUInt32Number TempDest) +{ + cmsHPROFILE hICC; + cmsPipeline* Pipeline; + BCHSWADJUSTS bchsw; + cmsCIExyY WhitePnt; + cmsStage* CLUT; + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + cmsUInt32Number i; + + bchsw.Brightness = Bright; + bchsw.Contrast = Contrast; + bchsw.Hue = Hue; + bchsw.Saturation = Saturation; + if (TempSrc == TempDest) { + + bchsw.lAdjustWP = FALSE; + } + else { + bchsw.lAdjustWP = TRUE; + cmsWhitePointFromTemp(&WhitePnt, TempSrc); + cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); + cmsWhitePointFromTemp(&WhitePnt, TempDest); + cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); + + } + + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; + + cmsSetDeviceClass(hICC, cmsSigAbstractClass); + cmsSetColorSpace(hICC, cmsSigLabData); + cmsSetPCS(hICC, cmsSigLabData); + + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); + + // Creates a Pipeline with 3D grid only + Pipeline = cmsPipelineAlloc(ContextID, 3, 3); + if (Pipeline == NULL) { + cmsCloseProfile(hICC); + return NULL; + } + + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; + CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); + if (CLUT == NULL) goto Error; + + + if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { + + // Shouldn't reach here + goto Error; + } + + if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) { + goto Error; + } + + // Create tags + if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; + + cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); + + cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); + + // Pipeline is already on virtual profile + cmsPipelineFree(Pipeline); + + // Ok, done + return hICC; + +Error: + cmsPipelineFree(Pipeline); + cmsCloseProfile(hICC); + return NULL; +} + + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(cmsUInt32Number nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + cmsUInt32Number TempSrc, + cmsUInt32Number TempDest) +{ + return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest); +} + + +// Creates a fake NULL profile. This profile return 1 channel as always 0. +// Is useful only for gamut checking tricks +cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) +{ + cmsHPROFILE hProfile; + cmsPipeline* LUT = NULL; + cmsStage* PostLin; + cmsStage* OutLin; + cmsToneCurve* EmptyTab[3]; + cmsUInt16Number Zero[2] = { 0, 0 }; + const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 }; + + hProfile = cmsCreateProfilePlaceholder(ContextID); + if (!hProfile) // can't allocate + return NULL; + + cmsSetProfileVersion(hProfile, 4.3); + + if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error; + + + cmsSetDeviceClass(hProfile, cmsSigOutputClass); + cmsSetColorSpace(hProfile, cmsSigGrayData); + cmsSetPCS(hProfile, cmsSigLabData); + + // Create a valid ICC 4 structure + LUT = cmsPipelineAlloc(ContextID, 3, 1); + if (LUT == NULL) goto Error; + + EmptyTab[0] = EmptyTab[1] = EmptyTab[2] = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); + PostLin = cmsStageAllocToneCurves(ContextID, 3, EmptyTab); + OutLin = cmsStageAllocToneCurves(ContextID, 1, EmptyTab); + cmsFreeToneCurve(EmptyTab[0]); + + if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin)) + goto Error; + + if (!cmsPipelineInsertStage(LUT, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL))) + goto Error; + + if (!cmsPipelineInsertStage(LUT, cmsAT_END, OutLin)) + goto Error; + + if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error; + if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; + + cmsPipelineFree(LUT); + return hProfile; + +Error: + + if (LUT != NULL) + cmsPipelineFree(LUT); + + if (hProfile != NULL) + cmsCloseProfile(hProfile); + + return NULL; +} + +cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void) +{ + return cmsCreateNULLProfileTHR(NULL); +} + + +static +int IsPCS(cmsColorSpaceSignature ColorSpace) +{ + return (ColorSpace == cmsSigXYZData || + ColorSpace == cmsSigLabData); +} + + +static +void FixColorSpaces(cmsHPROFILE hProfile, + cmsColorSpaceSignature ColorSpace, + cmsColorSpaceSignature PCS, + cmsUInt32Number dwFlags) +{ + if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) { + + if (IsPCS(ColorSpace) && IsPCS(PCS)) { + + cmsSetDeviceClass(hProfile, cmsSigAbstractClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); + return; + } + + if (IsPCS(ColorSpace) && !IsPCS(PCS)) { + + cmsSetDeviceClass(hProfile, cmsSigOutputClass); + cmsSetPCS(hProfile, ColorSpace); + cmsSetColorSpace(hProfile, PCS); + return; + } + + if (IsPCS(PCS) && !IsPCS(ColorSpace)) { + + cmsSetDeviceClass(hProfile, cmsSigInputClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); + return; + } + } + + cmsSetDeviceClass(hProfile, cmsSigLinkClass); + cmsSetColorSpace(hProfile, ColorSpace); + cmsSetPCS(hProfile, PCS); +} + + + +// This function creates a named color profile dumping all the contents of transform to a single profile +// In this way, LittleCMS may be used to "group" several named color databases into a single profile. +// It has, however, several minor limitations. PCS is always Lab, which is not very critic since this +// is the normal PCS for named color profiles. +static +cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) +{ + _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; + cmsHPROFILE hICC = NULL; + cmsUInt32Number i, nColors; + cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL; + + // Create an empty placeholder + hICC = cmsCreateProfilePlaceholder(v->ContextID); + if (hICC == NULL) return NULL; + + // Critical information + cmsSetDeviceClass(hICC, cmsSigNamedColorClass); + cmsSetColorSpace(hICC, v ->ExitColorSpace); + cmsSetPCS(hICC, cmsSigLabData); + + // Tag profile with information + if (!SetTextTags(hICC, L"Named color devicelink")) goto Error; + + Original = cmsGetNamedColorList(xform); + if (Original == NULL) goto Error; + + nColors = cmsNamedColorCount(Original); + nc2 = cmsDupNamedColorList(Original); + if (nc2 == NULL) goto Error; + + // Colorant count now depends on the output space + nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut); + + // Make sure we have proper formatters + cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX, + FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace)) + | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace))); + + // Apply the transfor to colorants. + for (i=0; i < nColors; i++) { + cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1); + } + + if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error; + cmsFreeNamedColorList(nc2); + + return hICC; + +Error: + if (hICC != NULL) cmsCloseProfile(hICC); + return NULL; +} + + +// This structure holds information about which MPU can be stored on a profile based on the version + +typedef struct { + cmsBool IsV4; // Is a V4 tag? + cmsTagSignature RequiredTag; // Set to 0 for both types + cmsTagTypeSignature LutType; // The LUT type + int nTypes; // Number of types (up to 5) + cmsStageSignature MpeTypes[5]; // 5 is the maximum number + +} cmsAllowedLUT; + +#define cmsSig0 ((cmsTagSignature) 0) + +static const cmsAllowedLUT AllowedLUTTypes[] = { + + { FALSE, cmsSig0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, + { FALSE, cmsSig0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, + { FALSE, cmsSig0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType } }, + { TRUE, cmsSig0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType } }, + { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, + { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, + { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, + { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }}, + { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, + { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}, + { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }} +}; + +#define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT)) + +// Check a single entry +static +cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) +{ + cmsStage* mpe; + int n; + + for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { + + if (n > Tab ->nTypes) return FALSE; + if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; + } + + return (n == Tab ->nTypes); +} + + +static +const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag) +{ + cmsUInt32Number n; + + for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) { + + const cmsAllowedLUT* Tab = AllowedLUTTypes + n; + + if (IsV4 ^ Tab -> IsV4) continue; + if ((Tab ->RequiredTag != 0) && (Tab ->RequiredTag != DestinationTag)) continue; + + if (CheckOne(Tab, Lut)) return Tab; + } + + return NULL; +} + + +// Does convert a transform into a device link profile +cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags) +{ + cmsHPROFILE hProfile = NULL; + cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut; + int ColorSpaceBitsIn, ColorSpaceBitsOut; + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + cmsPipeline* LUT = NULL; + cmsStage* mpe; + cmsContext ContextID = cmsGetTransformContextID(hTransform); + const cmsAllowedLUT* AllowedLUT; + cmsTagSignature DestinationTag; + cmsProfileClassSignature deviceClass; + + _cmsAssert(hTransform != NULL); + + // Get the first mpe to check for named color + mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut); + + // Check if is a named color transform + if (mpe != NULL) { + + if (cmsStageType(mpe) == cmsSigNamedColorElemType) { + return CreateNamedColorDevicelink(hTransform); + } + } + + // First thing to do is to get a copy of the transformation + LUT = cmsPipelineDup(xform ->Lut); + if (LUT == NULL) return NULL; + + // Time to fix the Lab2/Lab4 issue. + if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) { + + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID))) + goto Error; + } + + // On the output side too. Note that due to V2/V4 PCS encoding on lab we cannot fix white misalignments + if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) { + + dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; + if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; + } + + + hProfile = cmsCreateProfilePlaceholder(ContextID); + if (!hProfile) goto Error; // can't allocate + + cmsSetProfileVersion(hProfile, Version); + + FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags); + + // Optimize the LUT and precalculate a devicelink + + ChansIn = cmsChannelsOf(xform -> EntryColorSpace); + ChansOut = cmsChannelsOf(xform -> ExitColorSpace); + + ColorSpaceBitsIn = _cmsLCMScolorSpace(xform -> EntryColorSpace); + ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace); + + FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2); + FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2); + + deviceClass = cmsGetDeviceClass(hProfile); + + if (deviceClass == cmsSigOutputClass) + DestinationTag = cmsSigBToA0Tag; + else + DestinationTag = cmsSigAToB0Tag; + + // Check if the profile/version can store the result + if (dwFlags & cmsFLAGS_FORCE_CLUT) + AllowedLUT = NULL; + else + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); + + if (AllowedLUT == NULL) { + + // Try to optimize + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); + + } + + // If no way, then force CLUT that for sure can be written + if (AllowedLUT == NULL) { + + cmsStage* FirstStage; + cmsStage* LastStage; + + dwFlags |= cmsFLAGS_FORCE_CLUT; + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + + // Put identity curves if needed + FirstStage = cmsPipelineGetPtrToFirstStage(LUT); + if (FirstStage != NULL && FirstStage ->Type != cmsSigCurveSetElemType) + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn))) + goto Error; + + LastStage = cmsPipelineGetPtrToLastStage(LUT); + if (LastStage != NULL && LastStage ->Type != cmsSigCurveSetElemType) + if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut))) + goto Error; + + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); + } + + // Somethings is wrong... + if (AllowedLUT == NULL) { + goto Error; + } + + + if (dwFlags & cmsFLAGS_8BITS_DEVICELINK) + cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE); + + // Tag profile with information + if (!SetTextTags(hProfile, L"devicelink")) goto Error; + + // Store result + if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error; + + + if (xform -> InputColorant != NULL) { + if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error; + } + + if (xform -> OutputColorant != NULL) { + if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error; + } + + if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) { + if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error; + } + + // Set the white point + if (deviceClass == cmsSigInputClass) { + if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error; + } + else { + if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error; + } + + + // Per 7.2.15 in spec 4.3 + cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent); + + cmsPipelineFree(LUT); + return hProfile; + +Error: + if (LUT != NULL) cmsPipelineFree(LUT); + cmsCloseProfile(hProfile); + return NULL; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmswtpnt.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmswtpnt.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmswtpnt.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmswtpnt.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,379 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + + +// D50 - Widely used +const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void) +{ + static cmsCIEXYZ D50XYZ = {cmsD50X, cmsD50Y, cmsD50Z}; + + return &D50XYZ; +} + +const cmsCIExyY* CMSEXPORT cmsD50_xyY(void) +{ + static cmsCIExyY D50xyY; + + cmsXYZ2xyY(&D50xyY, cmsD50_XYZ()); + + return &D50xyY; +} + +// Obtains WhitePoint from Temperature +cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK) +{ + cmsFloat64Number x, y; + cmsFloat64Number T, T2, T3; + // cmsFloat64Number M1, M2; + + _cmsAssert(WhitePoint != NULL); + + T = TempK; + T2 = T*T; // Square + T3 = T2*T; // Cube + + // For correlated color temperature (T) between 4000K and 7000K: + + if (T >= 4000. && T <= 7000.) + { + x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; + } + else + // or for correlated color temperature (T) between 7000K and 25000K: + + if (T > 7000.0 && T <= 25000.0) + { + x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; + } + else { + cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp"); + return FALSE; + } + + // Obtain y(x) + y = -3.000*(x*x) + 2.870*x - 0.275; + + // wave factors (not used, but here for futures extensions) + + // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); + // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); + + WhitePoint -> x = x; + WhitePoint -> y = y; + WhitePoint -> Y = 1.0; + + return TRUE; +} + + + +typedef struct { + + cmsFloat64Number mirek; // temp (in microreciprocal kelvin) + cmsFloat64Number ut; // u coord of intersection w/ blackbody locus + cmsFloat64Number vt; // v coord of intersection w/ blackbody locus + cmsFloat64Number tt; // slope of ISOTEMPERATURE. line + + } ISOTEMPERATURE; + +static const ISOTEMPERATURE isotempdata[] = { +// {Mirek, Ut, Vt, Tt } + {0, 0.18006, 0.26352, -0.24341}, + {10, 0.18066, 0.26589, -0.25479}, + {20, 0.18133, 0.26846, -0.26876}, + {30, 0.18208, 0.27119, -0.28539}, + {40, 0.18293, 0.27407, -0.30470}, + {50, 0.18388, 0.27709, -0.32675}, + {60, 0.18494, 0.28021, -0.35156}, + {70, 0.18611, 0.28342, -0.37915}, + {80, 0.18740, 0.28668, -0.40955}, + {90, 0.18880, 0.28997, -0.44278}, + {100, 0.19032, 0.29326, -0.47888}, + {125, 0.19462, 0.30141, -0.58204}, + {150, 0.19962, 0.30921, -0.70471}, + {175, 0.20525, 0.31647, -0.84901}, + {200, 0.21142, 0.32312, -1.0182 }, + {225, 0.21807, 0.32909, -1.2168 }, + {250, 0.22511, 0.33439, -1.4512 }, + {275, 0.23247, 0.33904, -1.7298 }, + {300, 0.24010, 0.34308, -2.0637 }, + {325, 0.24702, 0.34655, -2.4681 }, + {350, 0.25591, 0.34951, -2.9641 }, + {375, 0.26400, 0.35200, -3.5814 }, + {400, 0.27218, 0.35407, -4.3633 }, + {425, 0.28039, 0.35577, -5.3762 }, + {450, 0.28863, 0.35714, -6.7262 }, + {475, 0.29685, 0.35823, -8.5955 }, + {500, 0.30505, 0.35907, -11.324 }, + {525, 0.31320, 0.35968, -15.628 }, + {550, 0.32129, 0.36011, -23.325 }, + {575, 0.32931, 0.36038, -40.770 }, + {600, 0.33724, 0.36051, -116.45 } +}; + +#define NISO sizeof(isotempdata)/sizeof(ISOTEMPERATURE) + + +// Robertson's method +cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint) +{ + cmsUInt32Number j; + cmsFloat64Number us,vs; + cmsFloat64Number uj,vj,tj,di,dj,mi,mj; + cmsFloat64Number xs, ys; + + _cmsAssert(WhitePoint != NULL); + _cmsAssert(TempK != NULL); + + di = mi = 0; + xs = WhitePoint -> x; + ys = WhitePoint -> y; + + // convert (x,y) to CIE 1960 (u,WhitePoint) + + us = (2*xs) / (-xs + 6*ys + 1.5); + vs = (3*ys) / (-xs + 6*ys + 1.5); + + + for (j=0; j < NISO; j++) { + + uj = isotempdata[j].ut; + vj = isotempdata[j].vt; + tj = isotempdata[j].tt; + mj = isotempdata[j].mirek; + + dj = ((vs - vj) - tj * (us - uj)) / sqrt(1.0 + tj * tj); + + if ((j != 0) && (di/dj < 0.0)) { + + // Found a match + *TempK = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi)); + return TRUE; + } + + di = dj; + mi = mj; + } + + // Not found + return FALSE; +} + + +// Compute chromatic adaptation matrix using Chad as cone matrix + +static +cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, + const cmsCIEXYZ* SourceWhitePoint, + const cmsCIEXYZ* DestWhitePoint, + const cmsMAT3* Chad) + +{ + + cmsMAT3 Chad_Inv; + cmsVEC3 ConeSourceXYZ, ConeSourceRGB; + cmsVEC3 ConeDestXYZ, ConeDestRGB; + cmsMAT3 Cone, Tmp; + + + Tmp = *Chad; + if (!_cmsMAT3inverse(&Tmp, &Chad_Inv)) return FALSE; + + _cmsVEC3init(&ConeSourceXYZ, SourceWhitePoint -> X, + SourceWhitePoint -> Y, + SourceWhitePoint -> Z); + + _cmsVEC3init(&ConeDestXYZ, DestWhitePoint -> X, + DestWhitePoint -> Y, + DestWhitePoint -> Z); + + _cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ); + _cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ); + + // Build matrix + _cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0); + _cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0); + _cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]); + + + // Normalize + _cmsMAT3per(&Tmp, &Cone, Chad); + _cmsMAT3per(Conversion, &Chad_Inv, &Tmp); + + return TRUE; +} + +// Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll +// The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed +cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll) +{ + cmsMAT3 LamRigg = {{ // Bradford matrix + {{ 0.8951, 0.2664, -0.1614 }}, + {{ -0.7502, 1.7135, 0.0367 }}, + {{ 0.0389, -0.0685, 1.0296 }} + }}; + + if (ConeMatrix == NULL) + ConeMatrix = &LamRigg; + + return ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix); +} + +// Same as anterior, but assuming D50 destination. White point is given in xyY +static +cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt) +{ + cmsCIEXYZ Dn; + cmsMAT3 Bradford; + cmsMAT3 Tmp; + + cmsxyY2XYZ(&Dn, SourceWhitePt); + + if (!_cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ())) return FALSE; + + Tmp = *r; + _cmsMAT3per(r, &Bradford, &Tmp); + + return TRUE; +} + +// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ +// This is just an approximation, I am not handling all the non-linear +// aspects of the RGB to XYZ process, and assumming that the gamma correction +// has transitive property in the transformation chain. +// +// the alghoritm: +// +// - First I build the absolute conversion matrix using +// primaries in XYZ. This matrix is next inverted +// - Then I eval the source white point across this matrix +// obtaining the coeficients of the transformation +// - Then, I apply these coeficients to the original matrix +// +cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs) +{ + cmsVEC3 WhitePoint, Coef; + cmsMAT3 Result, Primaries; + cmsFloat64Number xn, yn; + cmsFloat64Number xr, yr; + cmsFloat64Number xg, yg; + cmsFloat64Number xb, yb; + + xn = WhitePt -> x; + yn = WhitePt -> y; + xr = Primrs -> Red.x; + yr = Primrs -> Red.y; + xg = Primrs -> Green.x; + yg = Primrs -> Green.y; + xb = Primrs -> Blue.x; + yb = Primrs -> Blue.y; + + // Build Primaries matrix + _cmsVEC3init(&Primaries.v[0], xr, xg, xb); + _cmsVEC3init(&Primaries.v[1], yr, yg, yb); + _cmsVEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); + + + // Result = Primaries ^ (-1) inverse matrix + if (!_cmsMAT3inverse(&Primaries, &Result)) + return FALSE; + + + _cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); + + // Across inverse primaries ... + _cmsMAT3eval(&Coef, &Result, &WhitePoint); + + // Give us the Coefs, then I build transformation matrix + _cmsVEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); + _cmsVEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); + _cmsVEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb)); + + + return _cmsAdaptMatrixToD50(r, WhitePt); + +} + + +// Adapts a color to a given illuminant. Original color is expected to have +// a SourceWhitePt white point. +cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, + const cmsCIEXYZ* SourceWhitePt, + const cmsCIEXYZ* Illuminant, + const cmsCIEXYZ* Value) +{ + cmsMAT3 Bradford; + cmsVEC3 In, Out; + + _cmsAssert(Result != NULL); + _cmsAssert(SourceWhitePt != NULL); + _cmsAssert(Illuminant != NULL); + _cmsAssert(Value != NULL); + + if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE; + + _cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z); + _cmsMAT3eval(&Out, &Bradford, &In); + + Result -> X = Out.n[0]; + Result -> Y = Out.n[1]; + Result -> Z = Out.n[2]; + + return TRUE; +} + + diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsxform.c openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsxform.c --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/cmsxform.c 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/cmsxform.c 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1394 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "lcms2_internal.h" + +// Transformations stuff +// ----------------------------------------------------------------------- + +#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0 + +// The Context0 observer adaptation state. +_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + +// Init and duplicate observer adaptation state +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AdaptationStateContext]; + } + else { + from = &AdaptationStateChunk; + } + + ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType)); +} + + +// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all +// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states. +cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d) +{ + cmsFloat64Number prev; + _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext); + + // Get previous value for return + prev = ptr ->AdaptationState; + + // Set the value if d is positive or zero + if (d >= 0.0) { + + ptr ->AdaptationState = d; + } + + // Always return previous value + return prev; +} + + +// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine +cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d) +{ + return cmsSetAdaptationStateTHR(NULL, d); +} + +// ----------------------------------------------------------------------- + +// Alarm codes for 16-bit transformations, because the fixed range of containers there are +// no values left to mark out of gamut. + +#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + +// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be +// encoded in 16 bits. +void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) +{ + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes)); +} + +// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context. +// Values are meant to be encoded in 16 bits. +void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) +{ + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes)); +} + +void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) +{ + _cmsAssert(NewAlarm != NULL); + + cmsSetAlarmCodesTHR(NULL, NewAlarm); +} + +void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS]) +{ + _cmsAssert(OldAlarm != NULL); + cmsGetAlarmCodesTHR(NULL, OldAlarm); +} + + +// Init and duplicate alarm codes +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AlarmCodesContext]; + } + else { + from = &AlarmCodesChunk; + } + + ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType)); +} + +// ----------------------------------------------------------------------- + +// Get rid of transform resources +void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform; + + _cmsAssert(p != NULL); + + if (p -> GamutCheck) + cmsPipelineFree(p -> GamutCheck); + + if (p -> Lut) + cmsPipelineFree(p -> Lut); + + if (p ->InputColorant) + cmsFreeNamedColorList(p ->InputColorant); + + if (p -> OutputColorant) + cmsFreeNamedColorList(p ->OutputColorant); + + if (p ->Sequence) + cmsFreeProfileSequenceDescription(p ->Sequence); + + if (p ->UserData) + p ->FreeUserData(p ->ContextID, p ->UserData); + + _cmsFree(p ->ContextID, (void *) p); +} + + +static +cmsUInt32Number PixelSize(cmsUInt32Number Format) +{ + cmsUInt32Number fmt_bytes = T_BYTES(Format); + + // For double, the T_BYTES field is zero + if (fmt_bytes == 0) + return sizeof(cmsUInt64Number); + + // Otherwise, it is already correct for all formats + return fmt_bytes; +} + + + + +// Apply transform. +void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size) + +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; + cmsStride stride; + + stride.BytesPerLineIn = 0; // Not used + stride.BytesPerLineOut = 0; + stride.BytesPerPlaneIn = Size * PixelSize(p->InputFormat); + stride.BytesPerPlaneOut = Size * PixelSize(p->OutputFormat); + + p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride); +} + + +// This is a legacy stride for planar +void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size, cmsUInt32Number Stride) + +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; + cmsStride stride; + + stride.BytesPerLineIn = 0; + stride.BytesPerLineOut = 0; + stride.BytesPerPlaneIn = Stride; + stride.BytesPerPlaneOut = Stride; + + p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride); +} + +// This is the "fast" function for plugins +void CMSEXPORT cmsDoTransformLineStride(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + cmsUInt32Number BytesPerLineIn, + cmsUInt32Number BytesPerLineOut, + cmsUInt32Number BytesPerPlaneIn, + cmsUInt32Number BytesPerPlaneOut) + +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; + cmsStride stride; + + stride.BytesPerLineIn = BytesPerLineIn; + stride.BytesPerLineOut = BytesPerLineOut; + stride.BytesPerPlaneIn = BytesPerPlaneIn; + stride.BytesPerPlaneOut = BytesPerPlaneOut; + + p->xform(p, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, &stride); +} + + + +// Transform routines ---------------------------------------------------------------------------------------------------------- + +// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check. +// Note that because extended range, we can use a -1.0 value for out of gamut in this case. +static +void FloatXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS]; + cmsFloat32Number OutOfGamut; + cmsUInt32Number i, j, c, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + memset(fIn, 0, sizeof(fIn)); + memset(fOut, 0, sizeof(fOut)); + + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; + + for (j = 0; j < PixelsPerLine; j++) { + + accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn); + + // Any gamut chack to do? + if (p->GamutCheck != NULL) { + + // Evaluate gamut marker. + cmsPipelineEvalFloat(fIn, &OutOfGamut, p->GamutCheck); + + // Is current color out of gamut? + if (OutOfGamut > 0.0) { + + // Certainly, out of gamut + for (c = 0; c < cmsMAXCHANNELS; c++) + fOut[c] = -1.0; + + } + else { + // No, proceed normally + cmsPipelineEvalFloat(fIn, fOut, p->Lut); + } + } + else { + + // No gamut check at all + cmsPipelineEvalFloat(fIn, fOut, p->Lut); + } + + + output = p->ToOutputFloat(p, fOut, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } + +} + + +static +void NullFloatXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) + +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsFloat32Number fIn[cmsMAXCHANNELS]; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + memset(fIn, 0, sizeof(fIn)); + + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*) in + strideIn; + output = (cmsUInt8Number*) out + strideOut; + + for (j = 0; j < PixelsPerLine; j++) { + + accum = p->FromInputFloat(p, fIn, accum, Stride ->BytesPerPlaneIn); + output = p->ToOutputFloat(p, fIn, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } +} + +// 16 bit precision ----------------------------------------------------------------------------------------------------------- + +// Null transformation, only applies formatters. No cache +static +void NullXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS]; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + memset(wIn, 0, sizeof(wIn)); + + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; + + for (j = 0; j < PixelsPerLine; j++) { + + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); + output = p->ToOutput(p, wIn, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } + +} + + +// No gamut check, no cache, 16 bits +static +void PrecalculatedXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + CMSREGISTER cmsUInt8Number* accum; + CMSREGISTER cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + memset(wIn, 0, sizeof(wIn)); + memset(wOut, 0, sizeof(wOut)); + + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; + + for (j = 0; j < PixelsPerLine; j++) { + + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); + p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data); + output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } + +} + + +// Auxiliary: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical. +static +void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, + const cmsUInt16Number wIn[], + cmsUInt16Number wOut[]) +{ + cmsUInt16Number wOutOfGamut; + + p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data); + if (wOutOfGamut >= 1) { + + cmsUInt32Number i; + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext); + + for (i=0; i < p ->Lut->OutputChannels; i++) { + + wOut[i] = ContextAlarmCodes ->AlarmCodes[i]; + } + } + else + p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); +} + +// Gamut check, No cache, 16 bits. +static +void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + memset(wIn, 0, sizeof(wIn)); + memset(wOut, 0, sizeof(wOut)); + + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; + + for (j = 0; j < PixelsPerLine; j++) { + + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); + TransformOnePixelWithGamutCheck(p, wIn, wOut); + output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } +} + + +// No gamut check, Cache, 16 bits, +static +void CachedXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + _cmsCACHE Cache; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + // Empty buffers for quick memcmp + memset(wIn, 0, sizeof(wIn)); + memset(wOut, 0, sizeof(wOut)); + + // Get copy of zero cache + memcpy(&Cache, &p->Cache, sizeof(Cache)); + + strideIn = 0; + strideOut = 0; + + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; + + for (j = 0; j < PixelsPerLine; j++) { + + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); + + if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { + + memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); + } + else { + p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data); + + memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); + memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); + } + + output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } +} + +// All those nice features together +static +void CachedXFORMGamutCheck(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + _cmsCACHE Cache; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + // Empty buffers for quick memcmp + memset(wIn, 0, sizeof(wIn)); + memset(wOut, 0, sizeof(wOut)); + + // Get copy of zero cache + memcpy(&Cache, &p->Cache, sizeof(Cache)); + + strideIn = 0; + strideOut = 0; + + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; + + for (j = 0; j < PixelsPerLine; j++) { + + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); + + if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { + + memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); + } + else { + TransformOnePixelWithGamutCheck(p, wIn, wOut); + + memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); + memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); + } + + output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } +} + +// Transform plug-ins ---------------------------------------------------------------------------------------------------- + +// List of used-defined transform factories +typedef struct _cmsTransformCollection_st { + + _cmsTransform2Factory Factory; + cmsBool OldXform; // Factory returns xform function in the old style + + struct _cmsTransformCollection_st *Next; + +} _cmsTransformCollection; + +// The linked list head +_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginTransformList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTransformPluginChunkType newHead = { NULL }; + _cmsTransformCollection* entry; + _cmsTransformCollection* Anterior = NULL; + _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin]; + + // Walk the list copying all nodes + for (entry = head->TransformCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TransformCollection == NULL) + newHead.TransformCollection = newEntry; + } + + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType)); +} + +// Allocates memory for transform plugin factory +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginTransformList(ctx, src); + } + else { + static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL }; + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType)); + } +} + +// Adaptor for old versions of plug-in +static +void _cmsTransform2toTransformAdaptor(struct _cmstransform_struct *CMMcargo, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + + cmsUInt32Number i, strideIn, strideOut; + + _cmsHandleExtraChannels(CMMcargo, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + + for (i = 0; i < LineCount; i++) { + + void *accum = (cmsUInt8Number*)InputBuffer + strideIn; + void *output = (cmsUInt8Number*)OutputBuffer + strideOut; + + CMMcargo->OldXform(CMMcargo, accum, output, PixelsPerLine, Stride->BytesPerPlaneIn); + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } +} + + + +// Register new ways to transform +cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; + _cmsTransformCollection* fl; + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin); + + if (Data == NULL) { + + // Free the chain. Memory is safely freed at exit + ctx->TransformCollection = NULL; + return TRUE; + } + + // Factory callback is required + if (Plugin->factories.xform == NULL) return FALSE; + + + fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); + if (fl == NULL) return FALSE; + + // Check for full xform plug-ins previous to 2.8, we would need an adapter in that case + if (Plugin->base.ExpectedVersion < 2080) { + + fl->OldXform = TRUE; + } + else + fl->OldXform = FALSE; + + // Copy the parameters + fl->Factory = Plugin->factories.xform; + + // Keep linked list + fl ->Next = ctx->TransformCollection; + ctx->TransformCollection = fl; + + // All is ok + return TRUE; +} + + +void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn) +{ + _cmsAssert(CMMcargo != NULL); + CMMcargo ->UserData = ptr; + CMMcargo ->FreeUserData = FreePrivateDataFn; +} + +// returns the pointer defined by the plug-in to store private data +void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo) +{ + _cmsAssert(CMMcargo != NULL); + return CMMcargo ->UserData; +} + +// returns the current formatters +void CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput) +{ + _cmsAssert(CMMcargo != NULL); + if (FromInput) *FromInput = CMMcargo ->FromInput; + if (ToOutput) *ToOutput = CMMcargo ->ToOutput; +} + +void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput) +{ + _cmsAssert(CMMcargo != NULL); + if (FromInput) *FromInput = CMMcargo ->FromInputFloat; + if (ToOutput) *ToOutput = CMMcargo ->ToOutputFloat; +} + +// returns original flags +cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMMcargo) +{ + _cmsAssert(CMMcargo != NULL); + return CMMcargo->dwOriginalFlags; +} + +// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper +// for separated transforms. If this is the case, +static +_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, + cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) +{ + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin); + _cmsTransformCollection* Plugin; + + // Allocate needed memory + _cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); + if (!p) { + cmsPipelineFree(lut); + return NULL; + } + + // Store the proposed pipeline + p->Lut = lut; + + // Let's see if any plug-in want to do the transform by itself + if (p->Lut != NULL) { + + if (!(*dwFlags & cmsFLAGS_NOOPTIMIZE)) + { + for (Plugin = ctx->TransformCollection; + Plugin != NULL; + Plugin = Plugin->Next) { + + if (Plugin->Factory(&p->xform, &p->UserData, &p->FreeUserData, &p->Lut, InputFormat, OutputFormat, dwFlags)) { + + // Last plugin in the declaration order takes control. We just keep + // the original parameters as a logging. + // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default + // an optimized transform is not reusable. The plug-in can, however, change + // the flags and make it suitable. + + p->ContextID = ContextID; + p->InputFormat = *InputFormat; + p->OutputFormat = *OutputFormat; + p->dwOriginalFlags = *dwFlags; + + // Fill the formatters just in case the optimized routine is interested. + // No error is thrown if the formatter doesn't exist. It is up to the optimization + // factory to decide what to do in those cases. + p->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + + // Save the day? (Ignore the warning) + if (Plugin->OldXform) { + p->OldXform = (_cmsTransformFn)(void*)p->xform; + p->xform = _cmsTransform2toTransformAdaptor; + } + + return p; + } + } + } + + // Not suitable for the transform plug-in, let's check the pipeline plug-in + _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); + } + + // Check whatever this is a true floating point transform + if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { + + // Get formatter function always return a valid union, but the contents of this union may be NULL. + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; + + if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { + + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); + cmsDeleteTransform(p); + return NULL; + } + + if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { + + p ->xform = NullFloatXFORM; + } + else { + // Float transforms don't use cache, always are non-NULL + p ->xform = FloatXFORM; + } + + } + else { + + if (*InputFormat == 0 && *OutputFormat == 0) { + p ->FromInput = p ->ToOutput = NULL; + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; + } + else { + + cmsUInt32Number BytesPerPixelInput; + + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + + if (p ->FromInput == NULL || p ->ToOutput == NULL) { + + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); + cmsDeleteTransform(p); + return NULL; + } + + BytesPerPixelInput = T_BYTES(p ->InputFormat); + if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2) + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; + + } + + if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { + + p ->xform = NullXFORM; + } + else { + if (*dwFlags & cmsFLAGS_NOCACHE) { + + if (*dwFlags & cmsFLAGS_GAMUTCHECK) + p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cache + else + p ->xform = PrecalculatedXFORM; // No cache, no gamut check + } + else { + + if (*dwFlags & cmsFLAGS_GAMUTCHECK) + p ->xform = CachedXFORMGamutCheck; // Gamut check, cache + else + p ->xform = CachedXFORM; // No gamut check, cache + + } + } + } + + p ->InputFormat = *InputFormat; + p ->OutputFormat = *OutputFormat; + p ->dwOriginalFlags = *dwFlags; + p ->ContextID = ContextID; + p ->UserData = NULL; + return p; +} + +static +cmsBool GetXFormColorSpaces(cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output) +{ + cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut; + cmsColorSpaceSignature PostColorSpace; + cmsUInt32Number i; + + if (nProfiles == 0) return FALSE; + if (hProfiles[0] == NULL) return FALSE; + + *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]); + + for (i=0; i < nProfiles; i++) { + + cmsProfileClassSignature cls; + cmsHPROFILE hProfile = hProfiles[i]; + + int lIsInput = (PostColorSpace != cmsSigXYZData) && + (PostColorSpace != cmsSigLabData); + + if (hProfile == NULL) return FALSE; + + cls = cmsGetDeviceClass(hProfile); + + if (cls == cmsSigNamedColorClass) { + + ColorSpaceIn = cmsSig1colorData; + ColorSpaceOut = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile); + } + else + if (lIsInput || (cls == cmsSigLinkClass)) { + + ColorSpaceIn = cmsGetColorSpace(hProfile); + ColorSpaceOut = cmsGetPCS(hProfile); + } + else + { + ColorSpaceIn = cmsGetPCS(hProfile); + ColorSpaceOut = cmsGetColorSpace(hProfile); + } + + if (i==0) + *Input = ColorSpaceIn; + + PostColorSpace = ColorSpaceOut; + } + + *Output = PostColorSpace; + + return TRUE; +} + +// Check colorspace +static +cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat) +{ + int Space1 = (int) T_COLORSPACE(dwFormat); + int Space2 = _cmsLCMScolorSpace(Check); + + if (Space1 == PT_ANY) return TRUE; + if (Space1 == Space2) return TRUE; + + if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE; + if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE; + + return FALSE; +} + +// ---------------------------------------------------------------------------------------------------------------- + +// Jun-21-2000: Some profiles (those that comes with W2K) comes +// with the media white (media black?) x 100. Add a sanity check + +static +void NormalizeXYZ(cmsCIEXYZ* Dest) +{ + while (Dest -> X > 2. && + Dest -> Y > 2. && + Dest -> Z > 2.) { + + Dest -> X /= 10.; + Dest -> Y /= 10.; + Dest -> Z /= 10.; + } +} + +static +void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src) +{ + if (src == NULL) { + wtPt ->X = cmsD50X; + wtPt ->Y = cmsD50Y; + wtPt ->Z = cmsD50Z; + } + else { + wtPt ->X = src->X; + wtPt ->Y = src->Y; + wtPt ->Z = src->Z; + + NormalizeXYZ(wtPt); + } + +} + +// New to lcms 2.0 -- have all parameters available. +cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, + cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsHPROFILE hGamutProfile, + cmsUInt32Number nGamutPCSposition, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number dwFlags) +{ + _cmsTRANSFORM* xform; + cmsColorSpaceSignature EntryColorSpace; + cmsColorSpaceSignature ExitColorSpace; + cmsPipeline* Lut; + cmsUInt32Number LastIntent = Intents[nProfiles-1]; + + // If it is a fake transform + if (dwFlags & cmsFLAGS_NULLTRANSFORM) + { + return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags); + } + + // If gamut check is requested, make sure we have a gamut profile + if (dwFlags & cmsFLAGS_GAMUTCHECK) { + if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK; + } + + // On floating point transforms, inhibit cache + if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat)) + dwFlags |= cmsFLAGS_NOCACHE; + + // Mark entry/exit spaces + if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) { + cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform"); + return NULL; + } + + // Check if proper colorspaces + if (!IsProperColorSpace(EntryColorSpace, InputFormat)) { + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform"); + return NULL; + } + + if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) { + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform"); + return NULL; + } + + // Create a pipeline with all transformations + Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags); + if (Lut == NULL) { + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles"); + return NULL; + } + + // Check channel count + if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) || + (cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) { + cmsPipelineFree(Lut); + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted"); + return NULL; + } + + + // All seems ok + xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags); + if (xform == NULL) { + return NULL; + } + + // Keep values + xform ->EntryColorSpace = EntryColorSpace; + xform ->ExitColorSpace = ExitColorSpace; + xform ->RenderingIntent = Intents[nProfiles-1]; + + // Take white points + SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag)); + SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag)); + + + // Create a gamut check LUT if requested + if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK)) + xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles, + BPC, Intents, + AdaptationStates, + nGamutPCSposition, + hGamutProfile); + + + // Try to read input and output colorant table + if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) { + + // Input table can only come in this way. + xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag)); + } + + // Output is a little bit more complex. + if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) { + + // This tag may exist only on devicelink profiles. + if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) { + + // It may be NULL if error + xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)); + } + + } else { + + if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) { + + xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)); + } + } + + // Store the sequence of profiles + if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) { + xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles); + } + else + xform ->Sequence = NULL; + + // If this is a cached transform, init first value, which is zero (16 bits only) + if (!(dwFlags & cmsFLAGS_NOCACHE)) { + + memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn)); + + if (xform ->GamutCheck != NULL) { + TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut); + } + else { + + xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data); + } + + } + + return (cmsHTRANSFORM) xform; +} + +// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes. +cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags) +{ + cmsUInt32Number i; + cmsBool BPC[256]; + cmsUInt32Number Intents[256]; + cmsFloat64Number AdaptationStates[256]; + + if (nProfiles <= 0 || nProfiles > 255) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles); + return NULL; + } + + for (i=0; i < nProfiles; i++) { + BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE; + Intents[i] = Intent; + AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1); + } + + + return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags); +} + + + +cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags) +{ + + if (nProfiles <= 0 || nProfiles > 255) { + cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles); + return NULL; + } + + return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]), + hProfiles, + nProfiles, + InputFormat, + OutputFormat, + Intent, + dwFlags); +} + +cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID, + cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags) +{ + + cmsHPROFILE hArray[2]; + + hArray[0] = Input; + hArray[1] = Output; + + return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1U : 2U, InputFormat, OutputFormat, Intent, dwFlags); +} + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags) +{ + return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags); +} + + +cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, + cmsHPROFILE InputProfile, + cmsUInt32Number InputFormat, + cmsHPROFILE OutputProfile, + cmsUInt32Number OutputFormat, + cmsHPROFILE ProofingProfile, + cmsUInt32Number nIntent, + cmsUInt32Number ProofingIntent, + cmsUInt32Number dwFlags) +{ + cmsHPROFILE hArray[4]; + cmsUInt32Number Intents[4]; + cmsBool BPC[4]; + cmsFloat64Number Adaptation[4]; + cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE; + + + hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile; + Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent; + BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0; + + Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1); + + if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK))) + return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags); + + return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation, + ProofingProfile, 1, InputFormat, OutputFormat, dwFlags); + +} + + +cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, + cmsUInt32Number InputFormat, + cmsHPROFILE OutputProfile, + cmsUInt32Number OutputFormat, + cmsHPROFILE ProofingProfile, + cmsUInt32Number nIntent, + cmsUInt32Number ProofingIntent, + cmsUInt32Number dwFlags) +{ + return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile), + InputProfile, + InputFormat, + OutputProfile, + OutputFormat, + ProofingProfile, + nIntent, + ProofingIntent, + dwFlags); +} + + +// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed +cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform) +{ + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + + if (xform == NULL) return NULL; + return xform -> ContextID; +} + +// Grab the input/output formats +cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform) +{ + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + + if (xform == NULL) return 0; + return xform->InputFormat; +} + +cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform) +{ + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + + if (xform == NULL) return 0; + return xform->OutputFormat; +} + +// For backwards compatibility +cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat) +{ + _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; + cmsFormatter16 FromInput, ToOutput; + + + // We only can afford to change formatters if previous transform is at least 16 bits + if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) { + + cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision"); + return FALSE; + } + + FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + + if (FromInput == NULL || ToOutput == NULL) { + + cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); + return FALSE; + } + + xform ->InputFormat = InputFormat; + xform ->OutputFormat = OutputFormat; + xform ->FromInput = FromInput; + xform ->ToOutput = ToOutput; + return TRUE; +} diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/lcms2.h openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/lcms2.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/lcms2.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/lcms2.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1951 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2021 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// +// Version 2.12 +// + +#ifndef _lcms2_H + +// ********** Configuration toggles **************************************** + +// Uncomment this one if you are using big endian machines +// #define CMS_USE_BIG_ENDIAN 1 + +// Uncomment this one if your compiler/machine does NOT support the +// "long long" type. +// #define CMS_DONT_USE_INT64 1 + +// Uncomment this if your compiler doesn't work with fast floor function +// #define CMS_DONT_USE_FAST_FLOOR 1 + +// Uncomment this line if you want lcms to use the black point tag in profile, +// if commented, lcms will compute the black point by its own. +// It is safer to leave it commented out +// #define CMS_USE_PROFILE_BLACK_POINT_TAG 1 + +// Uncomment this line if you are compiling as C++ and want a C++ API +// #define CMS_USE_CPP_API + +// Uncomment this line if you need strict CGATS syntax. Makes CGATS files to +// require "KEYWORD" on undefined identifiers, keep it commented out unless needed +// #define CMS_STRICT_CGATS 1 + +// Uncomment to get rid of the tables for "half" float support +// #define CMS_NO_HALF_SUPPORT 1 + +// Uncomment to get rid of pthreads/windows dependency +// #define CMS_NO_PTHREADS 1 + +// Uncomment this for special windows mutex initialization (see lcms2_internal.h) +// #define CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT + +// Uncomment this to remove the "register" storage class +// #define CMS_NO_REGISTER_KEYWORD 1 + +// ********** End of configuration toggles ****************************** + +// Needed for streams +#include + +// Needed for portability (C99 per 7.1.2) +#include +#include +#include + +#ifndef CMS_USE_CPP_API +# ifdef __cplusplus +extern "C" { +# endif +#endif + +// Version/release +#define LCMS_VERSION 2120 + +// I will give the chance of redefining basic types for compilers that are not fully C99 compliant +#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED + +// Base types +typedef unsigned char cmsUInt8Number; // That is guaranteed by the C99 spec +typedef signed char cmsInt8Number; // That is guaranteed by the C99 spec + +#if CHAR_BIT != 8 +# error "Unable to find 8 bit type, unsupported compiler" +#endif + +// IEEE float storage numbers +typedef float cmsFloat32Number; +typedef double cmsFloat64Number; + +// 16-bit base types +#if (USHRT_MAX == 65535U) + typedef unsigned short cmsUInt16Number; +#elif (UINT_MAX == 65535U) + typedef unsigned int cmsUInt16Number; +#else +# error "Unable to find 16 bits unsigned type, unsupported compiler" +#endif + +#if (SHRT_MAX == 32767) + typedef short cmsInt16Number; +#elif (INT_MAX == 32767) + typedef int cmsInt16Number; +#else +# error "Unable to find 16 bits signed type, unsupported compiler" +#endif + +// 32-bit base type +#if (UINT_MAX == 4294967295U) + typedef unsigned int cmsUInt32Number; +#elif (ULONG_MAX == 4294967295U) + typedef unsigned long cmsUInt32Number; +#else +# error "Unable to find 32 bit unsigned type, unsupported compiler" +#endif + +#if (INT_MAX == +2147483647) + typedef int cmsInt32Number; +#elif (LONG_MAX == +2147483647) + typedef long cmsInt32Number; +#else +# error "Unable to find 32 bit signed type, unsupported compiler" +#endif + +// 64-bit base types +#ifndef CMS_DONT_USE_INT64 +# if (ULONG_MAX == 18446744073709551615U) + typedef unsigned long cmsUInt64Number; +# elif (ULLONG_MAX == 18446744073709551615U) + typedef unsigned long long cmsUInt64Number; +# else +# define CMS_DONT_USE_INT64 1 +# endif +# if (LONG_MAX == +9223372036854775807) + typedef long cmsInt64Number; +# elif (LLONG_MAX == +9223372036854775807) + typedef long long cmsInt64Number; +# else +# define CMS_DONT_USE_INT64 1 +# endif +#endif +#endif + +// Handle "register" keyword +#if defined(CMS_NO_REGISTER_KEYWORD) && !defined(CMS_DLL) && !defined(CMS_DLL_BUILD) +# define CMSREGISTER +#else +# define CMSREGISTER register +#endif + +// In the case 64 bit numbers are not supported by the compiler +#ifdef CMS_DONT_USE_INT64 + typedef cmsUInt32Number cmsUInt64Number[2]; + typedef cmsInt32Number cmsInt64Number[2]; +#endif + +// Derivative types +typedef cmsUInt32Number cmsSignature; +typedef cmsUInt16Number cmsU8Fixed8Number; +typedef cmsInt32Number cmsS15Fixed16Number; +typedef cmsUInt32Number cmsU16Fixed16Number; + +// Boolean type, which will be using the native integer +typedef int cmsBool; + +// Try to detect windows +#if defined (_WIN32) || defined(_WIN64) || defined(WIN32) || defined(_WIN32_) +# define CMS_IS_WINDOWS_ 1 +#endif + +#ifdef _MSC_VER +# define CMS_IS_WINDOWS_ 1 +#endif + +#ifdef __BORLANDC__ +# define CMS_IS_WINDOWS_ 1 +#endif + +// Try to detect big endian platforms. This list can be endless, so primarily rely on the configure script +// on Unix-like systems, and allow it to be set on the compiler command line using +// -DCMS_USE_BIG_ENDIAN or something similar +#ifdef CMS_USE_BIG_ENDIAN // set at compiler command line takes overall precedence + +# if CMS_USE_BIG_ENDIAN == 0 +# undef CMS_USE_BIG_ENDIAN +# endif + +#else // CMS_USE_BIG_ENDIAN + +# ifdef WORDS_BIGENDIAN // set by configure (or explicitly on compiler command line) +# define CMS_USE_BIG_ENDIAN 1 +# else // WORDS_BIGENDIAN +// Fall back to platform/compiler specific tests +# if defined(__sgi__) || defined(__sgi) || defined(sparc) +# define CMS_USE_BIG_ENDIAN 1 +# endif + +# if defined(__s390__) || defined(__s390x__) +# define CMS_USE_BIG_ENDIAN 1 +# endif + +# ifdef macintosh +# ifdef __BIG_ENDIAN__ +# define CMS_USE_BIG_ENDIAN 1 +# endif +# ifdef __LITTLE_ENDIAN__ +# undef CMS_USE_BIG_ENDIAN +# endif +# endif +# endif // WORDS_BIGENDIAN + +# if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) +# define CMS_USE_BIG_ENDIAN 1 +# endif + +#endif // CMS_USE_BIG_ENDIAN + + +// Calling convention -- this is hardly platform and compiler dependent +#ifdef CMS_IS_WINDOWS_ +# if defined(CMS_DLL) || defined(CMS_DLL_BUILD) +# ifdef __BORLANDC__ +# define CMSEXPORT __stdcall _export +# define CMSAPI +# else +# define CMSEXPORT __stdcall +# ifdef CMS_DLL_BUILD +# define CMSAPI __declspec(dllexport) +# else +# define CMSAPI __declspec(dllimport) +# endif +# endif +# else +# define CMSEXPORT +# define CMSAPI +# endif +#else // not Windows +# ifdef HAVE_FUNC_ATTRIBUTE_VISIBILITY +# define CMSEXPORT +# define CMSAPI __attribute__((visibility("default"))) +# else +# define CMSEXPORT +# define CMSAPI +# endif +#endif // CMS_IS_WINDOWS_ + +#ifdef HasTHREADS +# if HasTHREADS == 1 +# undef CMS_NO_PTHREADS +# else +# define CMS_NO_PTHREADS 1 +# endif +#endif + +// Some common definitions +#define cmsMAX_PATH 256 + +#ifndef FALSE +# define FALSE 0 +#endif +#ifndef TRUE +# define TRUE 1 +#endif + +// D50 XYZ normalized to Y=1.0 +#define cmsD50X 0.9642 +#define cmsD50Y 1.0 +#define cmsD50Z 0.8249 + +// V4 perceptual black +#define cmsPERCEPTUAL_BLACK_X 0.00336 +#define cmsPERCEPTUAL_BLACK_Y 0.0034731 +#define cmsPERCEPTUAL_BLACK_Z 0.00287 + +// Definitions in ICC spec +#define cmsMagicNumber 0x61637370 // 'acsp' +#define lcmsSignature 0x6c636d73 // 'lcms' + + +// Base ICC type definitions +typedef enum { + cmsSigChromaticityType = 0x6368726D, // 'chrm' + cmsSigColorantOrderType = 0x636C726F, // 'clro' + cmsSigColorantTableType = 0x636C7274, // 'clrt' + cmsSigCrdInfoType = 0x63726469, // 'crdi' + cmsSigCurveType = 0x63757276, // 'curv' + cmsSigDataType = 0x64617461, // 'data' + cmsSigDictType = 0x64696374, // 'dict' + cmsSigDateTimeType = 0x6474696D, // 'dtim' + cmsSigDeviceSettingsType = 0x64657673, // 'devs' + cmsSigLut16Type = 0x6d667432, // 'mft2' + cmsSigLut8Type = 0x6d667431, // 'mft1' + cmsSigLutAtoBType = 0x6d414220, // 'mAB ' + cmsSigLutBtoAType = 0x6d424120, // 'mBA ' + cmsSigMeasurementType = 0x6D656173, // 'meas' + cmsSigMultiLocalizedUnicodeType = 0x6D6C7563, // 'mluc' + cmsSigMultiProcessElementType = 0x6D706574, // 'mpet' + cmsSigNamedColorType = 0x6E636f6C, // 'ncol' -- DEPRECATED! + cmsSigNamedColor2Type = 0x6E636C32, // 'ncl2' + cmsSigParametricCurveType = 0x70617261, // 'para' + cmsSigProfileSequenceDescType = 0x70736571, // 'pseq' + cmsSigProfileSequenceIdType = 0x70736964, // 'psid' + cmsSigResponseCurveSet16Type = 0x72637332, // 'rcs2' + cmsSigS15Fixed16ArrayType = 0x73663332, // 'sf32' + cmsSigScreeningType = 0x7363726E, // 'scrn' + cmsSigSignatureType = 0x73696720, // 'sig ' + cmsSigTextType = 0x74657874, // 'text' + cmsSigTextDescriptionType = 0x64657363, // 'desc' + cmsSigU16Fixed16ArrayType = 0x75663332, // 'uf32' + cmsSigUcrBgType = 0x62666420, // 'bfd ' + cmsSigUInt16ArrayType = 0x75693136, // 'ui16' + cmsSigUInt32ArrayType = 0x75693332, // 'ui32' + cmsSigUInt64ArrayType = 0x75693634, // 'ui64' + cmsSigUInt8ArrayType = 0x75693038, // 'ui08' + cmsSigVcgtType = 0x76636774, // 'vcgt' + cmsSigViewingConditionsType = 0x76696577, // 'view' + cmsSigXYZType = 0x58595A20 // 'XYZ ' + + +} cmsTagTypeSignature; + +// Base ICC tag definitions +typedef enum { + cmsSigAToB0Tag = 0x41324230, // 'A2B0' + cmsSigAToB1Tag = 0x41324231, // 'A2B1' + cmsSigAToB2Tag = 0x41324232, // 'A2B2' + cmsSigBlueColorantTag = 0x6258595A, // 'bXYZ' + cmsSigBlueMatrixColumnTag = 0x6258595A, // 'bXYZ' + cmsSigBlueTRCTag = 0x62545243, // 'bTRC' + cmsSigBToA0Tag = 0x42324130, // 'B2A0' + cmsSigBToA1Tag = 0x42324131, // 'B2A1' + cmsSigBToA2Tag = 0x42324132, // 'B2A2' + cmsSigCalibrationDateTimeTag = 0x63616C74, // 'calt' + cmsSigCharTargetTag = 0x74617267, // 'targ' + cmsSigChromaticAdaptationTag = 0x63686164, // 'chad' + cmsSigChromaticityTag = 0x6368726D, // 'chrm' + cmsSigColorantOrderTag = 0x636C726F, // 'clro' + cmsSigColorantTableTag = 0x636C7274, // 'clrt' + cmsSigColorantTableOutTag = 0x636C6F74, // 'clot' + cmsSigColorimetricIntentImageStateTag = 0x63696973, // 'ciis' + cmsSigCopyrightTag = 0x63707274, // 'cprt' + cmsSigCrdInfoTag = 0x63726469, // 'crdi' + cmsSigDataTag = 0x64617461, // 'data' + cmsSigDateTimeTag = 0x6474696D, // 'dtim' + cmsSigDeviceMfgDescTag = 0x646D6E64, // 'dmnd' + cmsSigDeviceModelDescTag = 0x646D6464, // 'dmdd' + cmsSigDeviceSettingsTag = 0x64657673, // 'devs' + cmsSigDToB0Tag = 0x44324230, // 'D2B0' + cmsSigDToB1Tag = 0x44324231, // 'D2B1' + cmsSigDToB2Tag = 0x44324232, // 'D2B2' + cmsSigDToB3Tag = 0x44324233, // 'D2B3' + cmsSigBToD0Tag = 0x42324430, // 'B2D0' + cmsSigBToD1Tag = 0x42324431, // 'B2D1' + cmsSigBToD2Tag = 0x42324432, // 'B2D2' + cmsSigBToD3Tag = 0x42324433, // 'B2D3' + cmsSigGamutTag = 0x67616D74, // 'gamt' + cmsSigGrayTRCTag = 0x6b545243, // 'kTRC' + cmsSigGreenColorantTag = 0x6758595A, // 'gXYZ' + cmsSigGreenMatrixColumnTag = 0x6758595A, // 'gXYZ' + cmsSigGreenTRCTag = 0x67545243, // 'gTRC' + cmsSigLuminanceTag = 0x6C756d69, // 'lumi' + cmsSigMeasurementTag = 0x6D656173, // 'meas' + cmsSigMediaBlackPointTag = 0x626B7074, // 'bkpt' + cmsSigMediaWhitePointTag = 0x77747074, // 'wtpt' + cmsSigNamedColorTag = 0x6E636f6C, // 'ncol' // Deprecated by the ICC + cmsSigNamedColor2Tag = 0x6E636C32, // 'ncl2' + cmsSigOutputResponseTag = 0x72657370, // 'resp' + cmsSigPerceptualRenderingIntentGamutTag = 0x72696730, // 'rig0' + cmsSigPreview0Tag = 0x70726530, // 'pre0' + cmsSigPreview1Tag = 0x70726531, // 'pre1' + cmsSigPreview2Tag = 0x70726532, // 'pre2' + cmsSigProfileDescriptionTag = 0x64657363, // 'desc' + cmsSigProfileDescriptionMLTag = 0x6473636d, // 'dscm' + cmsSigProfileSequenceDescTag = 0x70736571, // 'pseq' + cmsSigProfileSequenceIdTag = 0x70736964, // 'psid' + cmsSigPs2CRD0Tag = 0x70736430, // 'psd0' + cmsSigPs2CRD1Tag = 0x70736431, // 'psd1' + cmsSigPs2CRD2Tag = 0x70736432, // 'psd2' + cmsSigPs2CRD3Tag = 0x70736433, // 'psd3' + cmsSigPs2CSATag = 0x70733273, // 'ps2s' + cmsSigPs2RenderingIntentTag = 0x70733269, // 'ps2i' + cmsSigRedColorantTag = 0x7258595A, // 'rXYZ' + cmsSigRedMatrixColumnTag = 0x7258595A, // 'rXYZ' + cmsSigRedTRCTag = 0x72545243, // 'rTRC' + cmsSigSaturationRenderingIntentGamutTag = 0x72696732, // 'rig2' + cmsSigScreeningDescTag = 0x73637264, // 'scrd' + cmsSigScreeningTag = 0x7363726E, // 'scrn' + cmsSigTechnologyTag = 0x74656368, // 'tech' + cmsSigUcrBgTag = 0x62666420, // 'bfd ' + cmsSigViewingCondDescTag = 0x76756564, // 'vued' + cmsSigViewingConditionsTag = 0x76696577, // 'view' + cmsSigVcgtTag = 0x76636774, // 'vcgt' + cmsSigMetaTag = 0x6D657461, // 'meta' + cmsSigArgyllArtsTag = 0x61727473 // 'arts' + +} cmsTagSignature; + + +// ICC Technology tag +typedef enum { + cmsSigDigitalCamera = 0x6463616D, // 'dcam' + cmsSigFilmScanner = 0x6673636E, // 'fscn' + cmsSigReflectiveScanner = 0x7273636E, // 'rscn' + cmsSigInkJetPrinter = 0x696A6574, // 'ijet' + cmsSigThermalWaxPrinter = 0x74776178, // 'twax' + cmsSigElectrophotographicPrinter = 0x6570686F, // 'epho' + cmsSigElectrostaticPrinter = 0x65737461, // 'esta' + cmsSigDyeSublimationPrinter = 0x64737562, // 'dsub' + cmsSigPhotographicPaperPrinter = 0x7270686F, // 'rpho' + cmsSigFilmWriter = 0x6670726E, // 'fprn' + cmsSigVideoMonitor = 0x7669646D, // 'vidm' + cmsSigVideoCamera = 0x76696463, // 'vidc' + cmsSigProjectionTelevision = 0x706A7476, // 'pjtv' + cmsSigCRTDisplay = 0x43525420, // 'CRT ' + cmsSigPMDisplay = 0x504D4420, // 'PMD ' + cmsSigAMDisplay = 0x414D4420, // 'AMD ' + cmsSigPhotoCD = 0x4B504344, // 'KPCD' + cmsSigPhotoImageSetter = 0x696D6773, // 'imgs' + cmsSigGravure = 0x67726176, // 'grav' + cmsSigOffsetLithography = 0x6F666673, // 'offs' + cmsSigSilkscreen = 0x73696C6B, // 'silk' + cmsSigFlexography = 0x666C6578, // 'flex' + cmsSigMotionPictureFilmScanner = 0x6D706673, // 'mpfs' + cmsSigMotionPictureFilmRecorder = 0x6D706672, // 'mpfr' + cmsSigDigitalMotionPictureCamera = 0x646D7063, // 'dmpc' + cmsSigDigitalCinemaProjector = 0x64636A70 // 'dcpj' + +} cmsTechnologySignature; + + +// ICC Color spaces +typedef enum { + cmsSigXYZData = 0x58595A20, // 'XYZ ' + cmsSigLabData = 0x4C616220, // 'Lab ' + cmsSigLuvData = 0x4C757620, // 'Luv ' + cmsSigYCbCrData = 0x59436272, // 'YCbr' + cmsSigYxyData = 0x59787920, // 'Yxy ' + cmsSigRgbData = 0x52474220, // 'RGB ' + cmsSigGrayData = 0x47524159, // 'GRAY' + cmsSigHsvData = 0x48535620, // 'HSV ' + cmsSigHlsData = 0x484C5320, // 'HLS ' + cmsSigCmykData = 0x434D594B, // 'CMYK' + cmsSigCmyData = 0x434D5920, // 'CMY ' + cmsSigMCH1Data = 0x4D434831, // 'MCH1' + cmsSigMCH2Data = 0x4D434832, // 'MCH2' + cmsSigMCH3Data = 0x4D434833, // 'MCH3' + cmsSigMCH4Data = 0x4D434834, // 'MCH4' + cmsSigMCH5Data = 0x4D434835, // 'MCH5' + cmsSigMCH6Data = 0x4D434836, // 'MCH6' + cmsSigMCH7Data = 0x4D434837, // 'MCH7' + cmsSigMCH8Data = 0x4D434838, // 'MCH8' + cmsSigMCH9Data = 0x4D434839, // 'MCH9' + cmsSigMCHAData = 0x4D434841, // 'MCHA' + cmsSigMCHBData = 0x4D434842, // 'MCHB' + cmsSigMCHCData = 0x4D434843, // 'MCHC' + cmsSigMCHDData = 0x4D434844, // 'MCHD' + cmsSigMCHEData = 0x4D434845, // 'MCHE' + cmsSigMCHFData = 0x4D434846, // 'MCHF' + cmsSigNamedData = 0x6e6d636c, // 'nmcl' + cmsSig1colorData = 0x31434C52, // '1CLR' + cmsSig2colorData = 0x32434C52, // '2CLR' + cmsSig3colorData = 0x33434C52, // '3CLR' + cmsSig4colorData = 0x34434C52, // '4CLR' + cmsSig5colorData = 0x35434C52, // '5CLR' + cmsSig6colorData = 0x36434C52, // '6CLR' + cmsSig7colorData = 0x37434C52, // '7CLR' + cmsSig8colorData = 0x38434C52, // '8CLR' + cmsSig9colorData = 0x39434C52, // '9CLR' + cmsSig10colorData = 0x41434C52, // 'ACLR' + cmsSig11colorData = 0x42434C52, // 'BCLR' + cmsSig12colorData = 0x43434C52, // 'CCLR' + cmsSig13colorData = 0x44434C52, // 'DCLR' + cmsSig14colorData = 0x45434C52, // 'ECLR' + cmsSig15colorData = 0x46434C52, // 'FCLR' + cmsSigLuvKData = 0x4C75764B // 'LuvK' + +} cmsColorSpaceSignature; + +// ICC Profile Class +typedef enum { + cmsSigInputClass = 0x73636E72, // 'scnr' + cmsSigDisplayClass = 0x6D6E7472, // 'mntr' + cmsSigOutputClass = 0x70727472, // 'prtr' + cmsSigLinkClass = 0x6C696E6B, // 'link' + cmsSigAbstractClass = 0x61627374, // 'abst' + cmsSigColorSpaceClass = 0x73706163, // 'spac' + cmsSigNamedColorClass = 0x6e6d636c // 'nmcl' + +} cmsProfileClassSignature; + +// ICC Platforms +typedef enum { + cmsSigMacintosh = 0x4150504C, // 'APPL' + cmsSigMicrosoft = 0x4D534654, // 'MSFT' + cmsSigSolaris = 0x53554E57, // 'SUNW' + cmsSigSGI = 0x53474920, // 'SGI ' + cmsSigTaligent = 0x54474E54, // 'TGNT' + cmsSigUnices = 0x2A6E6978 // '*nix' // From argyll -- Not official + +} cmsPlatformSignature; + +// Reference gamut +#define cmsSigPerceptualReferenceMediumGamut 0x70726d67 //'prmg' + +// For cmsSigColorimetricIntentImageStateTag +#define cmsSigSceneColorimetryEstimates 0x73636F65 //'scoe' +#define cmsSigSceneAppearanceEstimates 0x73617065 //'sape' +#define cmsSigFocalPlaneColorimetryEstimates 0x66706365 //'fpce' +#define cmsSigReflectionHardcopyOriginalColorimetry 0x72686F63 //'rhoc' +#define cmsSigReflectionPrintOutputColorimetry 0x72706F63 //'rpoc' + +// Multi process elements types +typedef enum { + cmsSigCurveSetElemType = 0x63767374, //'cvst' + cmsSigMatrixElemType = 0x6D617466, //'matf' + cmsSigCLutElemType = 0x636C7574, //'clut' + + cmsSigBAcsElemType = 0x62414353, // 'bACS' + cmsSigEAcsElemType = 0x65414353, // 'eACS' + + // Custom from here, not in the ICC Spec + cmsSigXYZ2LabElemType = 0x6C327820, // 'l2x ' + cmsSigLab2XYZElemType = 0x78326C20, // 'x2l ' + cmsSigNamedColorElemType = 0x6E636C20, // 'ncl ' + cmsSigLabV2toV4 = 0x32203420, // '2 4 ' + cmsSigLabV4toV2 = 0x34203220, // '4 2 ' + + // Identities + cmsSigIdentityElemType = 0x69646E20, // 'idn ' + + // Float to floatPCS + cmsSigLab2FloatPCS = 0x64326C20, // 'd2l ' + cmsSigFloatPCS2Lab = 0x6C326420, // 'l2d ' + cmsSigXYZ2FloatPCS = 0x64327820, // 'd2x ' + cmsSigFloatPCS2XYZ = 0x78326420, // 'x2d ' + cmsSigClipNegativesElemType = 0x636c7020 // 'clp ' + +} cmsStageSignature; + +// Types of CurveElements +typedef enum { + + cmsSigFormulaCurveSeg = 0x70617266, // 'parf' + cmsSigSampledCurveSeg = 0x73616D66, // 'samf' + cmsSigSegmentedCurve = 0x63757266 // 'curf' + +} cmsCurveSegSignature; + +// Used in ResponseCurveType +#define cmsSigStatusA 0x53746141 //'StaA' +#define cmsSigStatusE 0x53746145 //'StaE' +#define cmsSigStatusI 0x53746149 //'StaI' +#define cmsSigStatusT 0x53746154 //'StaT' +#define cmsSigStatusM 0x5374614D //'StaM' +#define cmsSigDN 0x444E2020 //'DN ' +#define cmsSigDNP 0x444E2050 //'DN P' +#define cmsSigDNN 0x444E4E20 //'DNN ' +#define cmsSigDNNP 0x444E4E50 //'DNNP' + +// Device attributes, currently defined values correspond to the low 4 bytes +// of the 8 byte attribute quantity +#define cmsReflective 0 +#define cmsTransparency 1 +#define cmsGlossy 0 +#define cmsMatte 2 + +// Common structures in ICC tags +typedef struct { + cmsUInt32Number len; + cmsUInt32Number flag; + cmsUInt8Number data[1]; + +} cmsICCData; + +// ICC date time +typedef struct { + cmsUInt16Number year; + cmsUInt16Number month; + cmsUInt16Number day; + cmsUInt16Number hours; + cmsUInt16Number minutes; + cmsUInt16Number seconds; + +} cmsDateTimeNumber; + +// ICC XYZ +typedef struct { + cmsS15Fixed16Number X; + cmsS15Fixed16Number Y; + cmsS15Fixed16Number Z; + +} cmsEncodedXYZNumber; + + +// Profile ID as computed by MD5 algorithm +typedef union { + cmsUInt8Number ID8[16]; + cmsUInt16Number ID16[8]; + cmsUInt32Number ID32[4]; + +} cmsProfileID; + + +// ---------------------------------------------------------------------------------------------- +// ICC profile internal base types. Strictly, shouldn't be declared in this header, but maybe +// somebody want to use this info for accessing profile header directly, so here it is. + +// Profile header -- it is 32-bit aligned, so no issues are expected on alignment +typedef struct { + cmsUInt32Number size; // Profile size in bytes + cmsSignature cmmId; // CMM for this profile + cmsUInt32Number version; // Format version number + cmsProfileClassSignature deviceClass; // Type of profile + cmsColorSpaceSignature colorSpace; // Color space of data + cmsColorSpaceSignature pcs; // PCS, XYZ or Lab only + cmsDateTimeNumber date; // Date profile was created + cmsSignature magic; // Magic Number to identify an ICC profile + cmsPlatformSignature platform; // Primary Platform + cmsUInt32Number flags; // Various bit settings + cmsSignature manufacturer; // Device manufacturer + cmsUInt32Number model; // Device model number + cmsUInt64Number attributes; // Device attributes + cmsUInt32Number renderingIntent;// Rendering intent + cmsEncodedXYZNumber illuminant; // Profile illuminant + cmsSignature creator; // Profile creator + cmsProfileID profileID; // Profile ID using MD5 + cmsInt8Number reserved[28]; // Reserved for future use + +} cmsICCHeader; + +// ICC base tag +typedef struct { + cmsTagTypeSignature sig; + cmsInt8Number reserved[4]; + +} cmsTagBase; + +// A tag entry in directory +typedef struct { + cmsTagSignature sig; // The tag signature + cmsUInt32Number offset; // Start of tag + cmsUInt32Number size; // Size in bytes + +} cmsTagEntry; + +// ---------------------------------------------------------------------------------------------- + +// Little CMS specific typedefs + +typedef void* cmsHANDLE ; // Generic handle +typedef void* cmsHPROFILE; // Opaque typedefs to hide internals +typedef void* cmsHTRANSFORM; + +#define cmsMAXCHANNELS 16 // Maximum number of channels in ICC profiles + +// Format of pixel is defined by one cmsUInt32Number, using bit fields as follows +// +// 2 1 0 +// 3 2 10987 6 5 4 3 2 1 098 7654 321 +// A O TTTTT U Y F P X S EEE CCCC BBB +// +// A: Floating point -- With this flag we can differentiate 16 bits as float and as int +// O: Optimized -- previous optimization already returns the final 8-bit value +// T: Pixeltype +// F: Flavor 0=MinIsBlack(Chocolate) 1=MinIsWhite(Vanilla) +// P: Planar? 0=Chunky, 1=Planar +// X: swap 16 bps endianness? +// S: Do swap? ie, BGR, KYMC +// E: Extra samples +// C: Channels (Samples per pixel) +// B: bytes per sample +// Y: Swap first - changes ABGR to BGRA and KCMY to CMYK + +#define FLOAT_SH(a) ((a) << 22) +#define OPTIMIZED_SH(s) ((s) << 21) +#define COLORSPACE_SH(s) ((s) << 16) +#define SWAPFIRST_SH(s) ((s) << 14) +#define FLAVOR_SH(s) ((s) << 13) +#define PLANAR_SH(p) ((p) << 12) +#define ENDIAN16_SH(e) ((e) << 11) +#define DOSWAP_SH(e) ((e) << 10) +#define EXTRA_SH(e) ((e) << 7) +#define CHANNELS_SH(c) ((c) << 3) +#define BYTES_SH(b) (b) + +// These macros unpack format specifiers into integers +#define T_FLOAT(a) (((a)>>22)&1) +#define T_OPTIMIZED(o) (((o)>>21)&1) +#define T_COLORSPACE(s) (((s)>>16)&31) +#define T_SWAPFIRST(s) (((s)>>14)&1) +#define T_FLAVOR(s) (((s)>>13)&1) +#define T_PLANAR(p) (((p)>>12)&1) +#define T_ENDIAN16(e) (((e)>>11)&1) +#define T_DOSWAP(e) (((e)>>10)&1) +#define T_EXTRA(e) (((e)>>7)&7) +#define T_CHANNELS(c) (((c)>>3)&15) +#define T_BYTES(b) ((b)&7) + + +// Pixel types +#define PT_ANY 0 // Don't check colorspace + // 1 & 2 are reserved +#define PT_GRAY 3 +#define PT_RGB 4 +#define PT_CMY 5 +#define PT_CMYK 6 +#define PT_YCbCr 7 +#define PT_YUV 8 // Lu'v' +#define PT_XYZ 9 +#define PT_Lab 10 +#define PT_YUVK 11 // Lu'v'K +#define PT_HSV 12 +#define PT_HLS 13 +#define PT_Yxy 14 + +#define PT_MCH1 15 +#define PT_MCH2 16 +#define PT_MCH3 17 +#define PT_MCH4 18 +#define PT_MCH5 19 +#define PT_MCH6 20 +#define PT_MCH7 21 +#define PT_MCH8 22 +#define PT_MCH9 23 +#define PT_MCH10 24 +#define PT_MCH11 25 +#define PT_MCH12 26 +#define PT_MCH13 27 +#define PT_MCH14 28 +#define PT_MCH15 29 + +#define PT_LabV2 30 // Identical to PT_Lab, but using the V2 old encoding + +// Some (not all!) representations + +#ifndef TYPE_RGB_8 // TYPE_RGB_8 is a very common identifier, so don't include ours + // if user has it already defined. + +#define TYPE_GRAY_8 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1)) +#define TYPE_GRAY_8_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1)) +#define TYPE_GRAY_16 (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_GRAY_16_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1)) +#define TYPE_GRAY_16_SE (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_GRAYA_8 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)) +#define TYPE_GRAYA_16 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_GRAYA_16_SE (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_GRAYA_8_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_GRAYA_16_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PLANAR_SH(1)) + +#define TYPE_RGB_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_RGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_BGR_8 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_BGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_RGB_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGB_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_RGB_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_BGR_16 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_BGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_BGR_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_RGBA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_RGBA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_RGBA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGBA_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ARGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1)) +#define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)) + +#define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_ABGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1)) +#define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1)) +#define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) + +#define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_CMY_8_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMY_16 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_CMY_16_PLANAR (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMY_16_SE (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_CMYK_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)) +#define TYPE_CMYKA_8 (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(1)) +#define TYPE_CMYK_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1)) +#define TYPE_YUVK_8 TYPE_CMYK_8_REV +#define TYPE_CMYK_8_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMYK_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)) +#define TYPE_CMYK_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1)) +#define TYPE_YUVK_16 TYPE_CMYK_16_REV +#define TYPE_CMYK_16_PLANAR (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMYK_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1)) + +#define TYPE_KYMC_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +#define TYPE_KCMY_8 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_8_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16 (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16_REV (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_KCMY_16_SE (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1)) + +#define TYPE_CMYK5_8 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(1)) +#define TYPE_CMYK5_16 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)) +#define TYPE_CMYK5_16_SE (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC5_8 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC5_16 (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC5_16_SE (COLORSPACE_SH(PT_MCH5)|CHANNELS_SH(5)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK6_8 (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(1)) +#define TYPE_CMYK6_8_PLANAR (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_CMYK6_16 (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2)) +#define TYPE_CMYK6_16_PLANAR (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_CMYK6_16_SE (COLORSPACE_SH(PT_MCH6)|CHANNELS_SH(6)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_CMYK7_8 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(1)) +#define TYPE_CMYK7_16 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)) +#define TYPE_CMYK7_16_SE (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC7_8 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC7_16 (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC7_16_SE (COLORSPACE_SH(PT_MCH7)|CHANNELS_SH(7)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK8_8 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(1)) +#define TYPE_CMYK8_16 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)) +#define TYPE_CMYK8_16_SE (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC8_8 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC8_16 (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC8_16_SE (COLORSPACE_SH(PT_MCH8)|CHANNELS_SH(8)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK9_8 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(1)) +#define TYPE_CMYK9_16 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)) +#define TYPE_CMYK9_16_SE (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC9_8 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC9_16 (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC9_16_SE (COLORSPACE_SH(PT_MCH9)|CHANNELS_SH(9)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK10_8 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(1)) +#define TYPE_CMYK10_16 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)) +#define TYPE_CMYK10_16_SE (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC10_8 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC10_16 (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC10_16_SE (COLORSPACE_SH(PT_MCH10)|CHANNELS_SH(10)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK11_8 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(1)) +#define TYPE_CMYK11_16 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)) +#define TYPE_CMYK11_16_SE (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC11_8 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC11_16 (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC11_16_SE (COLORSPACE_SH(PT_MCH11)|CHANNELS_SH(11)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) +#define TYPE_CMYK12_8 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(1)) +#define TYPE_CMYK12_16 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)) +#define TYPE_CMYK12_16_SE (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|ENDIAN16_SH(1)) +#define TYPE_KYMC12_8 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_KYMC12_16 (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_KYMC12_16_SE (COLORSPACE_SH(PT_MCH12)|CHANNELS_SH(12)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) + +// Colorimetric +#define TYPE_XYZ_16 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_Lab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_LabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)) + +#define TYPE_ALab_8 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ALabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_Lab_16 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_LabV2_16 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_Yxy_16 (COLORSPACE_SH(PT_Yxy)|CHANNELS_SH(3)|BYTES_SH(2)) + +// YCbCr +#define TYPE_YCbCr_8 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_YCbCr_8_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_YCbCr_16 (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_YCbCr_16_PLANAR (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_YCbCr_16_SE (COLORSPACE_SH(PT_YCbCr)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// YUV +#define TYPE_YUV_8 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_YUV_8_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_YUV_16 (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_YUV_16_PLANAR (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_YUV_16_SE (COLORSPACE_SH(PT_YUV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// HLS +#define TYPE_HLS_8 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_HLS_8_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_HLS_16 (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_HLS_16_PLANAR (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_HLS_16_SE (COLORSPACE_SH(PT_HLS)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// HSV +#define TYPE_HSV_8 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_HSV_8_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) +#define TYPE_HSV_16 (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_HSV_16_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) +#define TYPE_HSV_16_SE (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) + +// Named color index. Only 16 bits allowed (don't check colorspace) +#define TYPE_NAMED_COLOR_INDEX (CHANNELS_SH(1)|BYTES_SH(2)) + +// Float formatters. +#define TYPE_XYZ_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_Lab_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_LabA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_GRAY_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)) +#define TYPE_RGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)) + +#define TYPE_RGBA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_ARGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1)) +#define TYPE_BGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) +#define TYPE_BGRA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ABGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) + +#define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4)) + +// Floating point formatters. +// NOTE THAT 'BYTES' FIELD IS SET TO ZERO ON DLB because 8 bytes overflows the bitfield +#define TYPE_XYZ_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_Lab_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_GRAY_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(0)) +#define TYPE_RGB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)) +#define TYPE_BGR_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)|DOSWAP_SH(1)) +#define TYPE_CMYK_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0)) + +// IEEE 754-2008 "half" +#define TYPE_GRAY_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_RGB_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGBA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_CMYK_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)) + +#define TYPE_RGBA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_ARGB_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)) +#define TYPE_BGR_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_BGRA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ABGR_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) + +#endif + +// Colorspaces +typedef struct { + cmsFloat64Number X; + cmsFloat64Number Y; + cmsFloat64Number Z; + + } cmsCIEXYZ; + +typedef struct { + cmsFloat64Number x; + cmsFloat64Number y; + cmsFloat64Number Y; + + } cmsCIExyY; + +typedef struct { + cmsFloat64Number L; + cmsFloat64Number a; + cmsFloat64Number b; + + } cmsCIELab; + +typedef struct { + cmsFloat64Number L; + cmsFloat64Number C; + cmsFloat64Number h; + + } cmsCIELCh; + +typedef struct { + cmsFloat64Number J; + cmsFloat64Number C; + cmsFloat64Number h; + + } cmsJCh; + +typedef struct { + cmsCIEXYZ Red; + cmsCIEXYZ Green; + cmsCIEXYZ Blue; + + } cmsCIEXYZTRIPLE; + +typedef struct { + cmsCIExyY Red; + cmsCIExyY Green; + cmsCIExyY Blue; + + } cmsCIExyYTRIPLE; + +// Illuminant types for structs below +#define cmsILLUMINANT_TYPE_UNKNOWN 0x0000000 +#define cmsILLUMINANT_TYPE_D50 0x0000001 +#define cmsILLUMINANT_TYPE_D65 0x0000002 +#define cmsILLUMINANT_TYPE_D93 0x0000003 +#define cmsILLUMINANT_TYPE_F2 0x0000004 +#define cmsILLUMINANT_TYPE_D55 0x0000005 +#define cmsILLUMINANT_TYPE_A 0x0000006 +#define cmsILLUMINANT_TYPE_E 0x0000007 +#define cmsILLUMINANT_TYPE_F8 0x0000008 + +typedef struct { + cmsUInt32Number Observer; // 0 = unknown, 1=CIE 1931, 2=CIE 1964 + cmsCIEXYZ Backing; // Value of backing + cmsUInt32Number Geometry; // 0=unknown, 1=45/0, 0/45 2=0d, d/0 + cmsFloat64Number Flare; // 0..1.0 + cmsUInt32Number IlluminantType; + + } cmsICCMeasurementConditions; + +typedef struct { + cmsCIEXYZ IlluminantXYZ; // Not the same struct as CAM02, + cmsCIEXYZ SurroundXYZ; // This is for storing the tag + cmsUInt32Number IlluminantType; // viewing condition + + } cmsICCViewingConditions; + +// Get LittleCMS version (for shared objects) ----------------------------------------------------------------------------- + +CMSAPI int CMSEXPORT cmsGetEncodedCMMversion(void); + +// Support of non-standard functions -------------------------------------------------------------------------------------- + +CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2); +CMSAPI long int CMSEXPORT cmsfilelength(FILE* f); + + +// Context handling -------------------------------------------------------------------------------------------------------- + +// Each context holds its owns globals and its own plug-ins. There is a global context with the id = 0 for lecacy compatibility +// though using the global context is not recommended. Proper context handling makes lcms more thread-safe. + +typedef struct _cmsContext_struct* cmsContext; + +CMSAPI cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData); +CMSAPI void CMSEXPORT cmsDeleteContext(cmsContext ContextID); +CMSAPI cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData); +CMSAPI void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID); + +// Plug-In registering -------------------------------------------------------------------------------------------------- + +CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin); +CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin); +CMSAPI void CMSEXPORT cmsUnregisterPlugins(void); +CMSAPI void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID); + +// Error logging ---------------------------------------------------------------------------------------------------------- + +// There is no error handling at all. When a function fails, it returns proper value. +// For example, all create functions does return NULL on failure. Other may return FALSE. +// It may be interesting, for the developer, to know why the function is failing. +// for that reason, lcms2 does offer a logging function. This function will get +// an ENGLISH string with some clues on what is going wrong. You can show this +// info to the end user if you wish, or just create some sort of log on disk. +// The logging function should NOT terminate the program, as this obviously can leave +// unfreed resources. It is the programmer's responsibility to check each function +// return code to make sure it didn't fail. + +#define cmsERROR_UNDEFINED 0 +#define cmsERROR_FILE 1 +#define cmsERROR_RANGE 2 +#define cmsERROR_INTERNAL 3 +#define cmsERROR_NULL 4 +#define cmsERROR_READ 5 +#define cmsERROR_SEEK 6 +#define cmsERROR_WRITE 7 +#define cmsERROR_UNKNOWN_EXTENSION 8 +#define cmsERROR_COLORSPACE_CHECK 9 +#define cmsERROR_ALREADY_DEFINED 10 +#define cmsERROR_BAD_SIGNATURE 11 +#define cmsERROR_CORRUPTION_DETECTED 12 +#define cmsERROR_NOT_SUITABLE 13 + +// Error logger is called with the ContextID when a message is raised. This gives the +// chance to know which thread is responsible of the warning and any environment associated +// with it. Non-multithreading applications may safely ignore this parameter. +// Note that under certain special circumstances, ContextID may be NULL. +typedef void (* cmsLogErrorHandlerFunction)(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); + +// Allows user to set any specific logger +CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn); +CMSAPI void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn); + +// Conversions -------------------------------------------------------------------------------------------------------------- + +// Returns pointers to constant structs +CMSAPI const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void); +CMSAPI const cmsCIExyY* CMSEXPORT cmsD50_xyY(void); + +// Colorimetric space conversions +CMSAPI void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source); +CMSAPI void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source); +CMSAPI void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz); +CMSAPI void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab); +CMSAPI void CMSEXPORT cmsLab2LCh(cmsCIELCh*LCh, const cmsCIELab* Lab); +CMSAPI void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh); + +// Encoding /Decoding on PCS +CMSAPI void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3]); +CMSAPI void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3]); +CMSAPI void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* Lab); +CMSAPI void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* Lab); +CMSAPI void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fxyz, const cmsUInt16Number XYZ[3]); +CMSAPI void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ); + +// DeltaE metrics +CMSAPI cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2); +CMSAPI cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2); +CMSAPI cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2); +CMSAPI cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c); +CMSAPI cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh); + +// Temperature <-> Chromaticity (Black body) +CMSAPI cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK); +CMSAPI cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint); + +// Chromatic adaptation +CMSAPI cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, const cmsCIEXYZ* SourceWhitePt, + const cmsCIEXYZ* Illuminant, + const cmsCIEXYZ* Value); + +// CIECAM02 --------------------------------------------------------------------------------------------------- + +// Viewing conditions. Please note those are CAM model viewing conditions, and not the ICC tag viewing +// conditions, which I'm naming cmsICCViewingConditions to make differences evident. Unfortunately, the tag +// cannot deal with surround La, Yb and D value so is basically useless to store CAM02 viewing conditions. + + +#define AVG_SURROUND 1 +#define DIM_SURROUND 2 +#define DARK_SURROUND 3 +#define CUTSHEET_SURROUND 4 + +#define D_CALCULATE (-1) + +typedef struct { + cmsCIEXYZ whitePoint; + cmsFloat64Number Yb; + cmsFloat64Number La; + cmsUInt32Number surround; + cmsFloat64Number D_value; + + } cmsViewingConditions; + +CMSAPI cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC); +CMSAPI void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel); +CMSAPI void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut); +CMSAPI void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut); + + +// Tone curves ----------------------------------------------------------------------------------------- + +// This describes a curve segment. For a table of supported types, see the manual. User can increase the number of +// available types by using a proper plug-in. Parametric segments allow 10 parameters at most + +typedef struct { + cmsFloat32Number x0, x1; // Domain; for x0 < x <= x1 + cmsInt32Number Type; // Parametric type, Type == 0 means sampled segment. Negative values are reserved + cmsFloat64Number Params[10]; // Parameters if Type != 0 + cmsUInt32Number nGridPoints; // Number of grid points if Type == 0 + cmsFloat32Number* SampledPoints; // Points to an array of floats if Type == 0 + +} cmsCurveSegment; + +// The internal representation is none of your business. +typedef struct _cms_curve_struct cmsToneCurve; + +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, cmsUInt32Number nSegments, const cmsCurveSegment Segments[]); +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[]); +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma); +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsUInt32Number nEntries, const cmsUInt16Number values[]); +CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]); +CMSAPI void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve); +CMSAPI void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]); +CMSAPI cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* Src); +CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma); +CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsUInt32Number nResultSamples, const cmsToneCurve* InGamma); +CMSAPI cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, const cmsToneCurve* X, const cmsToneCurve* Y, cmsUInt32Number nPoints); +CMSAPI cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda); +CMSAPI cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v); +CMSAPI cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v); +CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* InGamma); +CMSAPI cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve); +CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t); +CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t); +CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t); +CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision); +CMSAPI cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t); + +// Tone curve tabular estimation +CMSAPI cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t); +CMSAPI const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t); + + +// Implements pipelines of multi-processing elements ------------------------------------------------------------- + +// Nothing to see here, move along +typedef struct _cmsPipeline_struct cmsPipeline; +typedef struct _cmsStage_struct cmsStage; + +// Those are hi-level pipelines +CMSAPI cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels); +CMSAPI void CMSEXPORT cmsPipelineFree(cmsPipeline* lut); +CMSAPI cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* Orig); + +CMSAPI cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut); +CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut); +CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut); + +CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut); +CMSAPI cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut); +CMSAPI cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut); + +CMSAPI void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut); +CMSAPI void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut); +CMSAPI cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], cmsFloat32Number Result[], cmsFloat32Number Hint[], const cmsPipeline* lut); +CMSAPI cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2); +CMSAPI cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On); + +// Where to place/locate the stages in the pipeline chain +typedef enum { cmsAT_BEGIN, cmsAT_END } cmsStageLoc; + +CMSAPI cmsBool CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe); +CMSAPI void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe); + +// This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements +// that conform the Pipeline. It should be called with the Pipeline, the number of expected elements and +// then a list of expected types followed with a list of double pointers to Stage elements. If +// the function founds a match with current pipeline, it fills the pointers and returns TRUE +// if not, returns FALSE without touching anything. +CMSAPI cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...); + +// Matrix has double precision and CLUT has only float precision. That is because an ICC profile can encode +// matrices with far more precision that CLUTS +CMSAPI cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels); +CMSAPI cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[]); +CMSAPI cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset); + +CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, cmsUInt32Number nGridPoints, cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsUInt16Number* Table); +CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, cmsUInt32Number nGridPoints, cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table); + +CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsUInt16Number* Table); +CMSAPI cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table); + +CMSAPI cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe); +CMSAPI void CMSEXPORT cmsStageFree(cmsStage* mpe); +CMSAPI cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe); + +CMSAPI cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe); +CMSAPI cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe); +CMSAPI cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe); +CMSAPI void* CMSEXPORT cmsStageData(const cmsStage* mpe); + +// Sampling +typedef cmsInt32Number (* cmsSAMPLER16) (CMSREGISTER const cmsUInt16Number In[], + CMSREGISTER cmsUInt16Number Out[], + CMSREGISTER void * Cargo); + +typedef cmsInt32Number (* cmsSAMPLERFLOAT)(CMSREGISTER const cmsFloat32Number In[], + CMSREGISTER cmsFloat32Number Out[], + CMSREGISTER void * Cargo); + +// Use this flag to prevent changes being written to destination +#define SAMPLER_INSPECT 0x01000000 + +// For CLUT only +CMSAPI cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags); +CMSAPI cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void* Cargo, cmsUInt32Number dwFlags); + +// Slicers +CMSAPI cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], + cmsSAMPLER16 Sampler, void * Cargo); + +CMSAPI cmsBool CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], + cmsSAMPLERFLOAT Sampler, void * Cargo); + +// Multilocalized Unicode management --------------------------------------------------------------------------------------- + +typedef struct _cms_MLU_struct cmsMLU; + +#define cmsNoLanguage "\0\0" +#define cmsNoCountry "\0\0" + +CMSAPI cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems); +CMSAPI void CMSEXPORT cmsMLUfree(cmsMLU* mlu); +CMSAPI cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu); + +CMSAPI cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + const char* ASCIIString); +CMSAPI cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + const wchar_t* WideString); + +CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize); + +CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize); + +CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char ObtainedLanguage[3], char ObtainedCountry[3]); + +CMSAPI cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu); + +CMSAPI cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, + cmsUInt32Number idx, + char LanguageCode[3], + char CountryCode[3]); + +// Undercolorremoval & black generation ------------------------------------------------------------------------------------- + +typedef struct { + cmsToneCurve* Ucr; + cmsToneCurve* Bg; + cmsMLU* Desc; + +} cmsUcrBg; + +// Screening ---------------------------------------------------------------------------------------------------------------- + +#define cmsPRINTER_DEFAULT_SCREENS 0x0001 +#define cmsFREQUENCE_UNITS_LINES_CM 0x0000 +#define cmsFREQUENCE_UNITS_LINES_INCH 0x0002 + +#define cmsSPOT_UNKNOWN 0 +#define cmsSPOT_PRINTER_DEFAULT 1 +#define cmsSPOT_ROUND 2 +#define cmsSPOT_DIAMOND 3 +#define cmsSPOT_ELLIPSE 4 +#define cmsSPOT_LINE 5 +#define cmsSPOT_SQUARE 6 +#define cmsSPOT_CROSS 7 + +typedef struct { + cmsFloat64Number Frequency; + cmsFloat64Number ScreenAngle; + cmsUInt32Number SpotShape; + +} cmsScreeningChannel; + +typedef struct { + cmsUInt32Number Flag; + cmsUInt32Number nChannels; + cmsScreeningChannel Channels[cmsMAXCHANNELS]; + +} cmsScreening; + + +// Named color ----------------------------------------------------------------------------------------------------------------- + +typedef struct _cms_NAMEDCOLORLIST_struct cmsNAMEDCOLORLIST; + +CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, + cmsUInt32Number n, + cmsUInt32Number ColorantCount, + const char* Prefix, const char* Suffix); + +CMSAPI void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v); +CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v); +CMSAPI cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* v, const char* Name, + cmsUInt16Number PCS[3], + cmsUInt16Number Colorant[cmsMAXCHANNELS]); + +CMSAPI cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* v); +CMSAPI cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* v, const char* Name); + +CMSAPI cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, + char* Name, + char* Prefix, + char* Suffix, + cmsUInt16Number* PCS, + cmsUInt16Number* Colorant); + +// Retrieve named color list from transform +CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform); + +// Profile sequence ----------------------------------------------------------------------------------------------------- + +// Profile sequence descriptor. Some fields come from profile sequence descriptor tag, others +// come from Profile Sequence Identifier Tag +typedef struct { + + cmsSignature deviceMfg; + cmsSignature deviceModel; + cmsUInt64Number attributes; + cmsTechnologySignature technology; + cmsProfileID ProfileID; + cmsMLU* Manufacturer; + cmsMLU* Model; + cmsMLU* Description; + +} cmsPSEQDESC; + +typedef struct { + + cmsUInt32Number n; + cmsContext ContextID; + cmsPSEQDESC* seq; + +} cmsSEQ; + +CMSAPI cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n); +CMSAPI cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq); +CMSAPI void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq); + +// Dictionaries -------------------------------------------------------------------------------------------------------- + +typedef struct _cmsDICTentry_struct { + + struct _cmsDICTentry_struct* Next; + + cmsMLU *DisplayName; + cmsMLU *DisplayValue; + wchar_t* Name; + wchar_t* Value; + +} cmsDICTentry; + +CMSAPI cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID); +CMSAPI void CMSEXPORT cmsDictFree(cmsHANDLE hDict); +CMSAPI cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict); + +CMSAPI cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue); +CMSAPI const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict); +CMSAPI const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e); + +// Access to Profile data ---------------------------------------------------------------------------------------------- +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID); + +CMSAPI cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile); +CMSAPI cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile); +CMSAPI cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n); +CMSAPI cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig); + +// Read and write pre-formatted data +CMSAPI void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig); +CMSAPI cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data); +CMSAPI cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest); +CMSAPI cmsTagSignature CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig); + +// Read and write raw data +CMSAPI cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* Buffer, cmsUInt32Number BufferSize); +CMSAPI cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size); + +// Access header data +#define cmsEmbeddedProfileFalse 0x00000000 +#define cmsEmbeddedProfileTrue 0x00000001 +#define cmsUseAnywhere 0x00000000 +#define cmsUseWithEmbeddedDataOnly 0x00000002 + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags); +CMSAPI void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID); +CMSAPI cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile); + +CMSAPI void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model); +CMSAPI void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags); +CMSAPI void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID); +CMSAPI void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent); + +CMSAPI cmsColorSpaceSignature + CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs); +CMSAPI cmsColorSpaceSignature + CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig); +CMSAPI cmsProfileClassSignature + CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig); +CMSAPI void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version); +CMSAPI cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile); + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile); +CMSAPI void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version); + +// How profiles may be used +#define LCMS_USED_AS_INPUT 0 +#define LCMS_USED_AS_OUTPUT 1 +#define LCMS_USED_AS_PROOF 2 + +CMSAPI cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection); +CMSAPI cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile); +CMSAPI cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection); + +// Translate form/to our notation to ICC +CMSAPI cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation); +CMSAPI int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace); + +CMSAPI cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace); + +// Build a suitable formatter for the colorspace of this profile. nBytes=1 means 8 bits, nBytes=2 means 16 bits. +CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat); +CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat); + + +// Localized info +typedef enum { + cmsInfoDescription = 0, + cmsInfoManufacturer = 1, + cmsInfoModel = 2, + cmsInfoCopyright = 3 +} cmsInfoType; + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize); + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize); + +// IO handlers ---------------------------------------------------------------------------------------------------------- + +typedef struct _cms_io_handler cmsIOHANDLER; + +CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode); +CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream); +CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode); +CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID); +CMSAPI cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile); +CMSAPI cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io); + +// MD5 message digest -------------------------------------------------------------------------------------------------- + +CMSAPI cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile); + +// Profile high level functions ------------------------------------------------------------------------------------------ + +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *ICCProfile, const char *sAccess); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char* sAccess); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char* sAccess); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void * MemPtr, cmsUInt32Number dwSize); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void * MemPtr, cmsUInt32Number dwSize); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write); +CMSAPI cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); + +CMSAPI cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName); +CMSAPI cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream); +CMSAPI cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded); +CMSAPI cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io); + +// Predefined virtual profiles ------------------------------------------------------------------------------------------ + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, + const cmsCIExyY* WhitePoint, + const cmsCIExyYTRIPLE* Primaries, + cmsToneCurve* const TransferFunction[3]); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint, + const cmsCIExyYTRIPLE* Primaries, + cmsToneCurve* const TransferFunction[3]); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, + const cmsCIExyY* WhitePoint, + const cmsToneCurve* TransferFunction); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint, + const cmsToneCurve* TransferFunction); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, + cmsColorSpaceSignature ColorSpace, + cmsToneCurve* const TransferFunctions[]); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace, + cmsToneCurve* const TransferFunctions[]); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, + cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit); + + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, + cmsUInt32Number nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + cmsUInt32Number TempSrc, + cmsUInt32Number TempDest); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(cmsUInt32Number nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + cmsUInt32Number TempSrc, + cmsUInt32Number TempDest); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void); + +// Converts a transform to a devicelink profile +CMSAPI cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags); + +// Intents ---------------------------------------------------------------------------------------------- + +// ICC Intents +#define INTENT_PERCEPTUAL 0 +#define INTENT_RELATIVE_COLORIMETRIC 1 +#define INTENT_SATURATION 2 +#define INTENT_ABSOLUTE_COLORIMETRIC 3 + +// Non-ICC intents +#define INTENT_PRESERVE_K_ONLY_PERCEPTUAL 10 +#define INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC 11 +#define INTENT_PRESERVE_K_ONLY_SATURATION 12 +#define INTENT_PRESERVE_K_PLANE_PERCEPTUAL 13 +#define INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC 14 +#define INTENT_PRESERVE_K_PLANE_SATURATION 15 + +// Call with NULL as parameters to get the intent count +CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); + +// Flags + +#define cmsFLAGS_NOCACHE 0x0040 // Inhibit 1-pixel cache +#define cmsFLAGS_NOOPTIMIZE 0x0100 // Inhibit optimizations +#define cmsFLAGS_NULLTRANSFORM 0x0200 // Don't transform anyway + +// Proofing flags +#define cmsFLAGS_GAMUTCHECK 0x1000 // Out of Gamut alarm +#define cmsFLAGS_SOFTPROOFING 0x4000 // Do softproofing + +// Misc +#define cmsFLAGS_BLACKPOINTCOMPENSATION 0x2000 +#define cmsFLAGS_NOWHITEONWHITEFIXUP 0x0004 // Don't fix scum dot +#define cmsFLAGS_HIGHRESPRECALC 0x0400 // Use more memory to give better accuracy +#define cmsFLAGS_LOWRESPRECALC 0x0800 // Use less memory to minimize resources + +// For devicelink creation +#define cmsFLAGS_8BITS_DEVICELINK 0x0008 // Create 8 bits devicelinks +#define cmsFLAGS_GUESSDEVICECLASS 0x0020 // Guess device class (for transform2devicelink) +#define cmsFLAGS_KEEP_SEQUENCE 0x0080 // Keep profile sequence for devicelink creation + +// Specific to a particular optimizations +#define cmsFLAGS_FORCE_CLUT 0x0002 // Force CLUT optimization +#define cmsFLAGS_CLUT_POST_LINEARIZATION 0x0001 // create postlinearization tables if possible +#define cmsFLAGS_CLUT_PRE_LINEARIZATION 0x0010 // create prelinearization tables if possible + +// Specific to unbounded mode +#define cmsFLAGS_NONEGATIVES 0x8000 // Prevent negative numbers in floating point transforms + +// Copy alpha channels when transforming +#define cmsFLAGS_COPY_ALPHA 0x04000000 // Alpha channels are copied on cmsDoTransform() + +// Fine-tune control over number of gridpoints +#define cmsFLAGS_GRIDPOINTS(n) (((n) & 0xFF) << 16) + +// CRD special +#define cmsFLAGS_NODEFAULTRESOURCEDEF 0x01000000 + +// Transforms --------------------------------------------------------------------------------------------------- + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID, + cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags); + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags); + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, + cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsHPROFILE Proofing, + cmsUInt32Number Intent, + cmsUInt32Number ProofingIntent, + cmsUInt32Number dwFlags); + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE Input, + cmsUInt32Number InputFormat, + cmsHPROFILE Output, + cmsUInt32Number OutputFormat, + cmsHPROFILE Proofing, + cmsUInt32Number Intent, + cmsUInt32Number ProofingIntent, + cmsUInt32Number dwFlags); + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags); + + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags); + + +CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, + cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsHPROFILE hGamutProfile, + cmsUInt32Number nGamutPCSposition, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + cmsUInt32Number dwFlags); + +CMSAPI void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform); + +CMSAPI void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, + const void * InputBuffer, + void * OutputBuffer, + cmsUInt32Number Size); + +CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, // Deprecated + const void * InputBuffer, + void * OutputBuffer, + cmsUInt32Number Size, + cmsUInt32Number Stride); + +CMSAPI void CMSEXPORT cmsDoTransformLineStride(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + cmsUInt32Number BytesPerLineIn, + cmsUInt32Number BytesPerLineOut, + cmsUInt32Number BytesPerPlaneIn, + cmsUInt32Number BytesPerPlaneOut); + + +CMSAPI void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); + + +CMSAPI void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, + const cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); + + + +// Adaptation state for absolute colorimetric intent +CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d); +CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d); + + + +// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed +CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform); + +// Grab the input/output formats +CMSAPI cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform); + +// For backwards compatibility +CMSAPI cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat); + + + +// PostScript ColorRenderingDictionary and ColorSpaceArray ---------------------------------------------------- + +typedef enum { cmsPS_RESOURCE_CSA, cmsPS_RESOURCE_CRD } cmsPSResourceType; + +// lcms2 unified method to access postscript color resources +CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, + cmsPSResourceType Type, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number dwFlags, + cmsIOHANDLER* io); + +CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags, void* Buffer, cmsUInt32Number dwBufferLen); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags, void* Buffer, cmsUInt32Number dwBufferLen); + + +// IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- + +CMSAPI cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID); +CMSAPI void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8); + +// Tables +CMSAPI cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8); +CMSAPI cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE hIT8, cmsUInt32Number nTable); + +// Persistence +CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName); +CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cmsUInt32Number len); +// CMSAPI cmsHANDLE CMSEXPORT cmsIT8LoadFromIOhandler(cmsContext ContextID, cmsIOHANDLER* io); + +CMSAPI cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName); +CMSAPI cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded); + +// Properties +CMSAPI const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8); +CMSAPI cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* cComment); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* cProp, const char *Str); +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val); +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val); +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer); +CMSAPI cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer); + + +CMSAPI const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* cProp); +CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp); +CMSAPI const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey); +CMSAPI cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames); +CMSAPI cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames); + +// Datasets +CMSAPI const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col); +CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, + const char* Val); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, + cmsFloat64Number Val); + +CMSAPI const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample); + + +CMSAPI cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE hIT8, const char* cPatch, const char* cSample); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, + const char* cSample, + const char *Val); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch, + const char* cSample, + cmsFloat64Number Val); + +CMSAPI int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample); +CMSAPI cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE hIT8, int n, const char *Sample); +CMSAPI int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames); + +CMSAPI const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer); +CMSAPI int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch); + +// The LABEL extension +CMSAPI int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType); + +CMSAPI cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample); + +// Formatter for double +CMSAPI void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter); + +// Gamut boundary description routines ------------------------------------------------------------------------------ + +CMSAPI cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID); +CMSAPI void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD); +CMSAPI cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab); +CMSAPI cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGDB, cmsUInt32Number dwFlags); +CMSAPI cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab); + +// Feature detection ---------------------------------------------------------------------------------------------- + +// Estimate the black point +CMSAPI cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags); +CMSAPI cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags); + +// Estimate total area coverage +CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile); + + +// Poor man's gamut mapping +CMSAPI cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, + double amax, double amin, + double bmax, double bmin); + +#ifndef CMS_USE_CPP_API +# ifdef __cplusplus + } +# endif +#endif + +#define _lcms2_H +#endif diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/lcms2_internal.h openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/lcms2_internal.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/lcms2_internal.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/lcms2_internal.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,1151 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// + +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#ifndef _lcms_internal_H + +// Include plug-in foundation +#ifndef _lcms_plugin_H +# include "lcms2_plugin.h" +#endif + +// ctype is part of C99 as per 7.1.2 +#include + +// assert macro is part of C99 as per 7.2 +#include + +// Some needed constants +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +#ifndef M_LOG10E +# define M_LOG10E 0.434294481903251827651 +#endif + +// BorlandC 5.5, VC2003 are broken on that +#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER < 1400)) // 1400 == VC++ 8.0 +#define sinf(x) (float)sin((float)x) +#define sqrtf(x) (float)sqrt((float)x) +#endif + + +// Alignment of ICC file format uses 4 bytes (cmsUInt32Number) +#define _cmsALIGNLONG(x) (((x)+(sizeof(cmsUInt32Number)-1)) & ~(sizeof(cmsUInt32Number)-1)) + +// Alignment to memory pointer + +// (Ultra)SPARC with gcc requires ptr alignment of 8 bytes +// even though sizeof(void *) is only four: for greatest flexibility +// allow the build to specify ptr alignment. +#ifndef CMS_PTR_ALIGNMENT +# define CMS_PTR_ALIGNMENT sizeof(void *) +#endif + +#define _cmsALIGNMEM(x) (((x)+(CMS_PTR_ALIGNMENT - 1)) & ~(CMS_PTR_ALIGNMENT - 1)) + +// Maximum encodeable values in floating point +#define MAX_ENCODEABLE_XYZ (1.0 + 32767.0/32768.0) +#define MIN_ENCODEABLE_ab2 (-128.0) +#define MAX_ENCODEABLE_ab2 ((65535.0/256.0) - 128.0) +#define MIN_ENCODEABLE_ab4 (-128.0) +#define MAX_ENCODEABLE_ab4 (127.0) + +// Maximum of channels for internal pipeline evaluation +#define MAX_STAGE_CHANNELS 128 + +// Unused parameter warning suppression +#define cmsUNUSED_PARAMETER(x) ((void)x) + +// The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999). +// unfortunately VisualC++ does not conform that +#if defined(_MSC_VER) || defined(__BORLANDC__) +# define cmsINLINE __inline +#else +# define cmsINLINE static inline +#endif + +// Allow signed overflow, we know this is harmless in this particular context +#if defined(__clang__) +# define CMS_NO_SANITIZE __attribute__((no_sanitize("signed-integer-overflow"))) +#else +# define CMS_NO_SANITIZE +#endif + +// Other replacement functions +#ifdef _MSC_VER +# ifndef snprintf +# define snprintf _snprintf +# endif +# ifndef vsnprintf +# define vsnprintf _vsnprintf +# endif + +/// Properly define some macros to accommodate +/// older MSVC versions. +# if defined(_MSC_VER) && _MSC_VER <= 1700 + #include + #define isnan _isnan + #define isinf(x) (!_finite((x))) +# endif + +#if !defined(_MSC_VER) && (defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L) + #if !defined(isinf) + #define isinf(x) (!finite((x))) + #endif +#endif + + +#endif + +// A fast way to convert from/to 16 <-> 8 bits +#define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb)) +#define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((cmsUInt32Number)(rgb) * 65281U + 8388608U) >> 24) & 0xFFU) + +// Code analysis is broken on asserts +#ifdef _MSC_VER +# if (_MSC_VER >= 1500) +# define _cmsAssert(a) { assert((a)); __analysis_assume((a)); } +# else +# define _cmsAssert(a) assert((a)) +# endif +#else +# define _cmsAssert(a) assert((a)) +#endif + +//--------------------------------------------------------------------------------- + +// Determinant lower than that are assumed zero (used on matrix invert) +#define MATRIX_DET_TOLERANCE 0.0001 + +//--------------------------------------------------------------------------------- + +// Fixed point +#define FIXED_TO_INT(x) ((x)>>16) +#define FIXED_REST_TO_INT(x) ((x)&0xFFFFU) +#define ROUND_FIXED_TO_INT(x) (((x)+0x8000)>>16) + +cmsINLINE cmsS15Fixed16Number _cmsToFixedDomain(int a) { return a + ((a + 0x7fff) / 0xffff); } +cmsINLINE int _cmsFromFixedDomain(cmsS15Fixed16Number a) { return a - ((a + 0x7fff) >> 16); } + +// ----------------------------------------------------------------------------------------------------------- + +// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon +// note than this only works in the range ..-32767...+32767 because +// mantissa is interpreted as 15.16 fixed point. +// The union is to avoid pointer aliasing overoptimization. +cmsINLINE int _cmsQuickFloor(cmsFloat64Number val) +{ +#ifdef CMS_DONT_USE_FAST_FLOOR + return (int) floor(val); +#else + const cmsFloat64Number _lcms_double2fixmagic = 68719476736.0 * 1.5; // 2^36 * 1.5, (52-16=36) uses limited precision to floor + union { + cmsFloat64Number val; + int halves[2]; + } temp; + + temp.val = val + _lcms_double2fixmagic; + +#ifdef CMS_USE_BIG_ENDIAN + return temp.halves[1] >> 16; +#else + return temp.halves[0] >> 16; +#endif +#endif +} + +// Fast floor restricted to 0..65535.0 +cmsINLINE cmsUInt16Number _cmsQuickFloorWord(cmsFloat64Number d) +{ + return (cmsUInt16Number) _cmsQuickFloor(d - 32767.0) + 32767U; +} + +// Floor to word, taking care of saturation +cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) +{ + d += 0.5; + if (d <= 0) return 0; + if (d >= 65535.0) return 0xffff; + + return _cmsQuickFloorWord(d); +} + +// Test bed entry points--------------------------------------------------------------- +#define CMSCHECKPOINT CMSAPI + +// Pthread support -------------------------------------------------------------------- +#ifndef CMS_NO_PTHREADS + +// This is the threading support. Unfortunately, it has to be platform-dependent because +// windows does not support pthreads. +#ifdef CMS_IS_WINDOWS_ + +#define WIN32_LEAN_AND_MEAN 1 +#include + + +// The locking scheme in LCMS requires a single 'top level' mutex +// to work. This is actually implemented on Windows as a +// CriticalSection, because they are lighter weight. With +// pthreads, this is statically inited. Unfortunately, windows +// can't officially statically init critical sections. +// +// We can work around this in 2 ways. +// +// 1) We can use a proper mutex purely to protect the init +// of the CriticalSection. This in turns requires us to protect +// the Mutex creation, which we can do using the snappily +// named InterlockedCompareExchangePointer API (present on +// windows XP and above). +// +// 2) In cases where we want to work on pre-Windows XP, we +// can use an even more horrible hack described below. +// +// So why wouldn't we always use 2)? Because not calling +// the init function for a critical section means it fails +// testing with ApplicationVerifier (and presumably similar +// tools). +// +// We therefore default to 1, and people who want to be able +// to run on pre-Windows XP boxes can build with: +// CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT +// defined. This is automatically set for builds using +// versions of MSVC that don't have this API available. +// +// From: http://locklessinc.com/articles/pthreads_on_windows/ +// The pthreads API has an initialization macro that has no correspondence to anything in +// the windows API. By investigating the internal definition of the critical section type, +// one may work out how to initialize one without calling InitializeCriticalSection(). +// The trick here is that InitializeCriticalSection() is not allowed to fail. It tries +// to allocate a critical section debug object, but if no memory is available, it sets +// the pointer to a specific value. (One would expect that value to be NULL, but it is +// actually (void *)-1 for some reason.) Thus we can use this special value for that +// pointer, and the critical section code will work. + +// The other important part of the critical section type to initialize is the number +// of waiters. This controls whether or not the mutex is locked. Fortunately, this +// part of the critical section is unlikely to change. Apparently, many programs +// already test critical sections to see if they are locked using this value, so +// Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical +// section, even when they changed the underlying algorithm to be more scalable. +// The final parts of the critical section object are unimportant, and can be set +// to zero for their defaults. This yields to an initialization macro: + +typedef CRITICAL_SECTION _cmsMutex; + +#ifdef _MSC_VER +# if (_MSC_VER >= 1800) +# pragma warning(disable : 26135) +# endif +#endif + +#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT +// If we are building with a version of MSVC smaller +// than 1400 (i.e. before VS2005) then we don't have +// the InterlockedCompareExchangePointer API, so use +// the old version. +# ifdef _MSC_VER +# if _MSC_VER < 1400 +# define CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT +# endif +# endif +#endif + +#ifdef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT +# define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG) -1,-1,0,0,0,0} +#else +# define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG)NULL,-1,0,0,0,0} +#endif + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + EnterCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + LeaveCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + InitializeCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + DeleteCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + EnterCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + LeaveCriticalSection(m); + return 0; +} + +#else + +// Rest of the wide world +#include + +#define CMS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +typedef pthread_mutex_t _cmsMutex; + + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + return pthread_mutex_lock(m); +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + return pthread_mutex_unlock(m); +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + return pthread_mutex_init(m, NULL); +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + return pthread_mutex_destroy(m); +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + return pthread_mutex_lock(m); +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + return pthread_mutex_unlock(m); +} + +#endif +#else + +#define CMS_MUTEX_INITIALIZER 0 +typedef int _cmsMutex; + + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + cmsUNUSED_PARAMETER(m); + return 0; +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + cmsUNUSED_PARAMETER(m); + return 0; +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + cmsUNUSED_PARAMETER(m); + return 0; +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + cmsUNUSED_PARAMETER(m); + return 0; +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + cmsUNUSED_PARAMETER(m); + return 0; +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + cmsUNUSED_PARAMETER(m); + return 0; +} +#endif + +// Plug-In registration --------------------------------------------------------------- + +// Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. +void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size); + +// Memory management +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Interpolation +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Parametric curves +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Formatters management +cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Tag type management +cmsBool _cmsRegisterTagTypePlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Tag management +cmsBool _cmsRegisterTagPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Intent management +cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Multi Process elements +cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Optimization +cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Transform +cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// Mutex +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + +// --------------------------------------------------------------------------------------------------------- + +// Suballocators. +typedef struct _cmsSubAllocator_chunk_st { + + cmsUInt8Number* Block; + cmsUInt32Number BlockSize; + cmsUInt32Number Used; + + struct _cmsSubAllocator_chunk_st* next; + +} _cmsSubAllocator_chunk; + + +typedef struct { + + cmsContext ContextID; + _cmsSubAllocator_chunk* h; + +} _cmsSubAllocator; + + +_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial); +void _cmsSubAllocDestroy(_cmsSubAllocator* s); +void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size); +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size); + +// ---------------------------------------------------------------------------------- + +// The context clients. +typedef enum { + + UserPtr, // User-defined pointer + Logger, + AlarmCodesContext, + AdaptationStateContext, + MemPlugin, + InterpPlugin, + CurvesPlugin, + FormattersPlugin, + TagTypePlugin, + TagPlugin, + IntentPlugin, + MPEPlugin, + OptimizationPlugin, + TransformPlugin, + MutexPlugin, + + // Last in list + MemoryClientMax + +} _cmsMemoryClient; + + +// Container for memory management plug-in. +typedef struct { + + _cmsMallocFnPtrType MallocPtr; + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; + +} _cmsMemPluginChunkType; + +// Copy memory management function pointers from plug-in to chunk, taking care of missing routines +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr); + +// Internal structure for context +struct _cmsContext_struct { + + struct _cmsContext_struct* Next; // Points to next context in the new style + _cmsSubAllocator* MemPool; // The memory pool that stores context data + + void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. + // If NULL, then it reverts to global Context0 + + _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overridden +}; + +// Returns a pointer to a valid context structure, including the global one if id is zero. +// Verifies the magic number. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID); + +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc); + + +// Chunks of context memory by plug-in client ------------------------------------------------------- + +// Those structures encapsulates all variables needed by the several context clients (mostly plug-ins) + +// Container for error logger -- not a plug-in +typedef struct { + + cmsLogErrorHandlerFunction LogErrorHandler; // Set to NULL for Context0 fallback + +} _cmsLogErrorChunkType; + +// The global Context0 storage for error logger +extern _cmsLogErrorChunkType _cmsLogErrorChunk; + +// Allocate and init error logger container. +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for alarm codes -- not a plug-in +typedef struct { + + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]; + +} _cmsAlarmCodesChunkType; + +// The global Context0 storage for alarm codes +extern _cmsAlarmCodesChunkType _cmsAlarmCodesChunk; + +// Allocate and init alarm codes container. +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for adaptation state -- not a plug-in +typedef struct { + + cmsFloat64Number AdaptationState; + +} _cmsAdaptationStateChunkType; + +// The global Context0 storage for adaptation state +extern _cmsAdaptationStateChunkType _cmsAdaptationStateChunk; + +// Allocate and init adaptation state container. +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + + +// The global Context0 storage for memory management +extern _cmsMemPluginChunkType _cmsMemPluginChunk; + +// Allocate and init memory management container. +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for interpolation plug-in +typedef struct { + + cmsInterpFnFactory Interpolators; + +} _cmsInterpPluginChunkType; + +// The global Context0 storage for interpolation plug-in +extern _cmsInterpPluginChunkType _cmsInterpPluginChunk; + +// Allocate and init interpolation container. +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for parametric curves plug-in +typedef struct { + + struct _cmsParametricCurvesCollection_st* ParametricCurves; + +} _cmsCurvesPluginChunkType; + +// The global Context0 storage for tone curves plug-in +extern _cmsCurvesPluginChunkType _cmsCurvesPluginChunk; + +// Allocate and init parametric curves container. +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for formatters plug-in +typedef struct { + + struct _cms_formatters_factory_list* FactoryList; + +} _cmsFormattersPluginChunkType; + +// The global Context0 storage for formatters plug-in +extern _cmsFormattersPluginChunkType _cmsFormattersPluginChunk; + +// Allocate and init formatters container. +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// This chunk type is shared by TagType plug-in and MPE Plug-in +typedef struct { + + struct _cmsTagTypeLinkedList_st* TagTypes; + +} _cmsTagTypePluginChunkType; + + +// The global Context0 storage for tag types plug-in +extern _cmsTagTypePluginChunkType _cmsTagTypePluginChunk; + + +// The global Context0 storage for mult process elements plug-in +extern _cmsTagTypePluginChunkType _cmsMPETypePluginChunk; + +// Allocate and init Tag types container. +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Allocate and init MPE container. +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Container for tag plug-in +typedef struct { + + struct _cmsTagLinkedList_st* Tag; + +} _cmsTagPluginChunkType; + + +// The global Context0 storage for tag plug-in +extern _cmsTagPluginChunkType _cmsTagPluginChunk; + +// Allocate and init Tag container. +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for intents plug-in +typedef struct { + + struct _cms_intents_list* Intents; + +} _cmsIntentsPluginChunkType; + + +// The global Context0 storage for intents plug-in +extern _cmsIntentsPluginChunkType _cmsIntentsPluginChunk; + +// Allocate and init intents container. +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for optimization plug-in +typedef struct { + + struct _cmsOptimizationCollection_st* OptimizationCollection; + +} _cmsOptimizationPluginChunkType; + + +// The global Context0 storage for optimizers plug-in +extern _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk; + +// Allocate and init optimizers container. +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for transform plug-in +typedef struct { + + struct _cmsTransformCollection_st* TransformCollection; + +} _cmsTransformPluginChunkType; + +// The global Context0 storage for full-transform replacement plug-in +extern _cmsTransformPluginChunkType _cmsTransformPluginChunk; + +// Allocate and init transform container. +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for mutex plug-in +typedef struct { + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} _cmsMutexPluginChunkType; + +// The global Context0 storage for mutex plug-in +extern _cmsMutexPluginChunkType _cmsMutexPluginChunk; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// ---------------------------------------------------------------------------------- +// MLU internal representation +typedef struct { + + cmsUInt16Number Language; + cmsUInt16Number Country; + + cmsUInt32Number StrW; // Offset to current unicode string + cmsUInt32Number Len; // Length in bytes + +} _cmsMLUentry; + +struct _cms_MLU_struct { + + cmsContext ContextID; + + // The directory + cmsUInt32Number AllocatedEntries; + cmsUInt32Number UsedEntries; + _cmsMLUentry* Entries; // Array of pointers to strings allocated in MemPool + + // The Pool + cmsUInt32Number PoolSize; // The maximum allocated size + cmsUInt32Number PoolUsed; // The used size + void* MemPool; // Pointer to begin of memory pool +}; + +// Named color list internal representation +typedef struct { + + char Name[cmsMAX_PATH]; + cmsUInt16Number PCS[3]; + cmsUInt16Number DeviceColorant[cmsMAXCHANNELS]; + +} _cmsNAMEDCOLOR; + +struct _cms_NAMEDCOLORLIST_struct { + + cmsUInt32Number nColors; + cmsUInt32Number Allocated; + cmsUInt32Number ColorantCount; + + char Prefix[33]; // Prefix and suffix are defined to be 32 characters at most + char Suffix[33]; + + _cmsNAMEDCOLOR* List; + + cmsContext ContextID; +}; + + +// ---------------------------------------------------------------------------------- + +// This is the internal struct holding profile details. + +// Maximum supported tags in a profile +#define MAX_TABLE_TAG 100 + +typedef struct _cms_iccprofile_struct { + + // I/O handler + cmsIOHANDLER* IOhandler; + + // The thread ID + cmsContext ContextID; + + // Creation time + struct tm Created; + + // Only most important items found in ICC profiles + cmsUInt32Number Version; + cmsProfileClassSignature DeviceClass; + cmsColorSpaceSignature ColorSpace; + cmsColorSpaceSignature PCS; + cmsUInt32Number RenderingIntent; + + cmsUInt32Number flags; + cmsUInt32Number manufacturer, model; + cmsUInt64Number attributes; + cmsUInt32Number creator; + + cmsProfileID ProfileID; + + // Dictionary + cmsUInt32Number TagCount; + cmsTagSignature TagNames[MAX_TABLE_TAG]; + cmsTagSignature TagLinked[MAX_TABLE_TAG]; // The tag to which is linked (0=none) + cmsUInt32Number TagSizes[MAX_TABLE_TAG]; // Size on disk + cmsUInt32Number TagOffsets[MAX_TABLE_TAG]; + cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked + void * TagPtrs[MAX_TABLE_TAG]; + cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types + // depending on profile version, so we keep track of the + // type handler for each tag in the list. + // Special + cmsBool IsWrite; + + // Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin + void * UsrMutex; + +} _cmsICCPROFILE; + +// IO helpers for profiles +cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc); +cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace); +int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks); + +// Tag types +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig); +cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig); +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig); + +// Error logging --------------------------------------------------------------------------------------------------------- + +void _cmsTagSignature2String(char String[5], cmsTagSignature sig); + +// Interpolation --------------------------------------------------------------------------------------------------------- + +CMSCHECKPOINT cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples, cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags); +cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags); +CMSCHECKPOINT void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p); +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p); + +// Curves ---------------------------------------------------------------------------------------------------------------- + +// This struct holds information about a segment, plus a pointer to the function that implements the evaluation. +// In the case of table-based, Eval pointer is set to NULL + +// The gamma function main structure +struct _cms_curve_struct { + + cmsInterpParams* InterpParams; // Private optimizations for interpolation + + cmsUInt32Number nSegments; // Number of segments in the curve. Zero for a 16-bit based tables + cmsCurveSegment* Segments; // The segments + cmsInterpParams** SegInterp; // Array of private optimizations for interpolation in table-based segments + + cmsParametricCurveEvaluator* Evals; // Evaluators (one per segment) + + // 16 bit Table-based representation follows + cmsUInt32Number nEntries; // Number of table elements + cmsUInt16Number* Table16; // The table itself. +}; + + +// Pipelines & Stages --------------------------------------------------------------------------------------------- + +// A single stage +struct _cmsStage_struct { + + cmsContext ContextID; + + cmsStageSignature Type; // Identifies the stage + cmsStageSignature Implements; // Identifies the *function* of the stage (for optimizations) + + cmsUInt32Number InputChannels; // Input channels -- for optimization purposes + cmsUInt32Number OutputChannels; // Output channels -- for optimization purposes + + _cmsStageEvalFn EvalPtr; // Points to fn that evaluates the stage (always in floating point) + _cmsStageDupElemFn DupElemPtr; // Points to a fn that duplicates the *data* of the stage + _cmsStageFreeElemFn FreePtr; // Points to a fn that sets the *data* of the stage free + + // A generic pointer to whatever memory needed by the stage + void* Data; + + // Maintains linked list (used internally) + struct _cmsStage_struct* Next; +}; + + +// Special Stages (cannot be saved) +CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocLab2XYZ(cmsContext ContextID); +CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocXYZ2Lab(cmsContext ContextID); +cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID); +CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocLabV2ToV4(cmsContext ContextID); +cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID); +CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocLabV4ToV2(cmsContext ContextID); +CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS); +CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocIdentityCurves(cmsContext ContextID, cmsUInt32Number nChannels); +CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocIdentityCLut(cmsContext ContextID, cmsUInt32Number nChan); +cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID); +cmsStage* _cmsStageClipNegatives(cmsContext ContextID, cmsUInt32Number nChannels); + + +// For curve set only +cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe); + +struct _cmsPipeline_struct { + + cmsStage* Elements; // Points to elements chain + cmsUInt32Number InputChannels, OutputChannels; + + // Data & evaluators + void *Data; + + _cmsPipelineEval16Fn Eval16Fn; + _cmsPipelineEvalFloatFn EvalFloatFn; + _cmsFreeUserDataFn FreeDataFn; + _cmsDupUserDataFn DupDataFn; + + cmsContext ContextID; // Environment + + cmsBool SaveAs8Bits; // Implementation-specific: save as 8 bits if possible +}; + +// LUT reading & creation ------------------------------------------------------------------------------------------- + +// Read tags using low-level function, provide necessary glue code to adapt versions, etc. All those return a brand new copy +// of the LUTS, since ownership of original is up to the profile. The user should free allocated resources. + +CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadInputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent); +CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent); +CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent); + +// Special values +cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile); +cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile); + +// Profile linker -------------------------------------------------------------------------------------------------- + +// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point +// compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS +// after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1) +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +// Sequence -------------------------------------------------------------------------------------------------------- + +cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile); +cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq); +cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]); + + +// LUT optimization ------------------------------------------------------------------------------------------------ + +CMSCHECKPOINT cmsUInt16Number CMSEXPORT _cmsQuantizeVal(cmsFloat64Number i, cmsUInt32Number MaxSamples); + +CMSAPI cmsUInt32Number CMSEXPORT _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags); + +cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, + cmsUInt16Number **White, + cmsUInt16Number **Black, + cmsUInt32Number *nOutputs); + +CMSAPI cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** Lut, + cmsUInt32Number Intent, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags ); + + +// Hi level LUT building ---------------------------------------------------------------------------------------------- + +cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsUInt32Number Intents[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number nGamutPCSposition, + cmsHPROFILE hGamut); + + +// Formatters ------------------------------------------------------------------------------------------------------------ + +#define cmsFLAGS_CAN_CHANGE_FORMATTER 0x02000000 // Allow change buffer format + +cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type); +cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type); + +CMSCHECKPOINT cmsFormatter CMSEXPORT _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags); + + +#ifndef CMS_NO_HALF_SUPPORT + +// Half float +CMSCHECKPOINT cmsFloat32Number CMSEXPORT _cmsHalf2Float(cmsUInt16Number h); +CMSCHECKPOINT cmsUInt16Number CMSEXPORT _cmsFloat2Half(cmsFloat32Number flt); + +#endif + +// Transform logic ------------------------------------------------------------------------------------------------------ + +struct _cmstransform_struct; + +typedef struct { + + // 1-pixel cache (16 bits only) + cmsUInt16Number CacheIn[cmsMAXCHANNELS]; + cmsUInt16Number CacheOut[cmsMAXCHANNELS]; + +} _cmsCACHE; + + + +// Transformation +typedef struct _cmstransform_struct { + + cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference + + // Points to transform code + _cmsTransform2Fn xform; + + // Formatters, cannot be embedded into LUT because cache + cmsFormatter16 FromInput; + cmsFormatter16 ToOutput; + + cmsFormatterFloat FromInputFloat; + cmsFormatterFloat ToOutputFloat; + + // 1-pixel cache seed for zero as input (16 bits, read only) + _cmsCACHE Cache; + + // A Pipeline holding the full (optimized) transform + cmsPipeline* Lut; + + // A Pipeline holding the gamut check. It goes from the input space to bilevel + cmsPipeline* GamutCheck; + + // Colorant tables + cmsNAMEDCOLORLIST* InputColorant; // Input Colorant table + cmsNAMEDCOLORLIST* OutputColorant; // Colorant table (for n chans > CMYK) + + // Informational only + cmsColorSpaceSignature EntryColorSpace; + cmsColorSpaceSignature ExitColorSpace; + + // White points (informative only) + cmsCIEXYZ EntryWhitePoint; + cmsCIEXYZ ExitWhitePoint; + + // Profiles used to create the transform + cmsSEQ* Sequence; + + cmsUInt32Number dwOriginalFlags; + cmsFloat64Number AdaptationState; + + // The intent of this transform. That is usually the last intent in the profilechain, but may differ + cmsUInt32Number RenderingIntent; + + // An id that uniquely identifies the running context. May be null. + cmsContext ContextID; + + // A user-defined pointer that can be used to store data for transform plug-ins + void* UserData; + _cmsFreeUserDataFn FreeUserData; + + // A way to provide backwards compatibility with full xform plugins + _cmsTransformFn OldXform; + +} _cmsTRANSFORM; + +// Copies extra channels from input to output if the original flags in the transform structure +// instructs to do so. This function is called on all standard transform functions. +void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride); + +// ----------------------------------------------------------------------------------------------------------------------- + +cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number InputFormat, + cmsUInt32Number OutputFormat, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + + +cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, + cmsUInt32Number nPoints, + cmsUInt32Number nProfiles, + const cmsUInt32Number Intents[], + const cmsHPROFILE hProfiles[], + const cmsBool BPC[], + const cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + +cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll); + +cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries); + + +#define _lcms_internal_H +#endif diff -Nru openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/lcms2_plugin.h openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/lcms2_plugin.h --- openjdk-17-17.0.3+7/src/java.desktop/share/native/liblcms/lcms2_plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/share/native/liblcms/lcms2_plugin.h 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,709 @@ +/* + * 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. + */ + +// This file is available under and governed by the GNU General Public +// License version 2 only, as published by the Free Software Foundation. +// However, the following notice accompanied the original version of this +// file: +// +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2020 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// +// This is the plug-in header file. Normal LittleCMS clients should not use it. +// It is provided for plug-in writters that may want to access the support +// functions to do low level operations. All plug-in related structures +// are defined here. Including this file forces to include the standard API too. + +#ifndef _lcms_plugin_H + +// Deal with Microsoft's attempt at deprecating C standard runtime functions +#ifdef _MSC_VER +# if (_MSC_VER >= 1400) +# ifndef _CRT_SECURE_NO_DEPRECATE +# define _CRT_SECURE_NO_DEPRECATE +# endif +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +# endif +# endif +#endif + +#ifndef _lcms2_H +#include "lcms2.h" +#endif + +// We need some standard C functions. +#include +#include +#include +#include +#include + + +#ifndef CMS_USE_CPP_API +# ifdef __cplusplus +extern "C" { +# endif +#endif + +// Vector & Matrix operations ----------------------------------------------------------------------- + +// Axis of the matrix/array. No specific meaning at all. +#define VX 0 +#define VY 1 +#define VZ 2 + +// Vectors +typedef struct { + cmsFloat64Number n[3]; + + } cmsVEC3; + +// 3x3 Matrix +typedef struct { + cmsVEC3 v[3]; + + } cmsMAT3; + +CMSAPI void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z); +CMSAPI void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b); +CMSAPI void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v); +CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v); +CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a); +CMSAPI cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b); + +CMSAPI void CMSEXPORT _cmsMAT3identity(cmsMAT3* a); +CMSAPI cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a); +CMSAPI void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b); +CMSAPI cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b); +CMSAPI cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b); +CMSAPI void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v); + + +// MD5 low level ------------------------------------------------------------------------------------- + +CMSAPI cmsHANDLE CMSEXPORT cmsMD5alloc(cmsContext ContextID); +CMSAPI void CMSEXPORT cmsMD5add(cmsHANDLE Handle, const cmsUInt8Number* buf, cmsUInt32Number len); +CMSAPI void CMSEXPORT cmsMD5finish(cmsProfileID* ProfileID, cmsHANDLE Handle); + +// Error logging ------------------------------------------------------------------------------------- + +CMSAPI void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...); + +// Memory management ---------------------------------------------------------------------------------- + +CMSAPI void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size); +CMSAPI void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size); +CMSAPI void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); +CMSAPI void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); +CMSAPI void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr); +CMSAPI void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size); + +// I/O handler ---------------------------------------------------------------------------------- + +struct _cms_io_handler { + + void* stream; // Associated stream, which is implemented differently depending on media. + + cmsContext ContextID; + cmsUInt32Number UsedSpace; + cmsUInt32Number ReportedSize; + char PhysicalFile[cmsMAX_PATH]; + + cmsUInt32Number (* Read)(struct _cms_io_handler* iohandler, void *Buffer, + cmsUInt32Number size, + cmsUInt32Number count); + cmsBool (* Seek)(struct _cms_io_handler* iohandler, cmsUInt32Number offset); + cmsBool (* Close)(struct _cms_io_handler* iohandler); + cmsUInt32Number (* Tell)(struct _cms_io_handler* iohandler); + cmsBool (* Write)(struct _cms_io_handler* iohandler, cmsUInt32Number size, + const void* Buffer); +}; + +// Endianness adjust functions +CMSAPI cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word); +CMSAPI cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number Value); +CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord); + +// Helper IO functions +CMSAPI cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n); +CMSAPI cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n); +CMSAPI cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ); +CMSAPI cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array); + +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n); +CMSAPI cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n); +CMSAPI cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ); +CMSAPI cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array); + +// ICC base tag +typedef struct { + cmsTagTypeSignature sig; + cmsInt8Number reserved[4]; + +} _cmsTagBase; + +// Type base helper functions +CMSAPI cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io); +CMSAPI cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig); + +// Alignment functions +CMSAPI cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io); +CMSAPI cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io); + +// To deal with text streams. 2K at most +CMSAPI cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...); + +// Fixed point helper functions +CMSAPI cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8); +CMSAPI cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val); + +CMSAPI cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32); +CMSAPI cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v); + +// Date/time helper functions +CMSAPI void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source); +CMSAPI void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest); + +//---------------------------------------------------------------------------------------------------------- + +// Shared callbacks for user data +typedef void (* _cmsFreeUserDataFn)(cmsContext ContextID, void* Data); +typedef void* (* _cmsDupUserDataFn)(cmsContext ContextID, const void* Data); + +//---------------------------------------------------------------------------------------------------------- + +// Plug-in foundation +#define cmsPluginMagicNumber 0x61637070 // 'acpp' + +#define cmsPluginMemHandlerSig 0x6D656D48 // 'memH' +#define cmsPluginInterpolationSig 0x696E7048 // 'inpH' +#define cmsPluginParametricCurveSig 0x70617248 // 'parH' +#define cmsPluginFormattersSig 0x66726D48 // 'frmH +#define cmsPluginTagTypeSig 0x74797048 // 'typH' +#define cmsPluginTagSig 0x74616748 // 'tagH' +#define cmsPluginRenderingIntentSig 0x696E7448 // 'intH' +#define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH' +#define cmsPluginOptimizationSig 0x6F707448 // 'optH' +#define cmsPluginTransformSig 0x7A666D48 // 'xfmH' +#define cmsPluginMutexSig 0x6D747A48 // 'mtxH' + +typedef struct _cmsPluginBaseStruct { + + cmsUInt32Number Magic; // 'acpp' signature + cmsUInt32Number ExpectedVersion; // Expected version of LittleCMS + cmsUInt32Number Type; // Type of plug-in + struct _cmsPluginBaseStruct* Next; // For multiple plugin definition. NULL for end of list. + +} cmsPluginBase; + +// Maximum number of types in a plugin array +#define MAX_TYPES_IN_LCMS_PLUGIN 20 + +//---------------------------------------------------------------------------------------------------------- + +// Memory handler. Each new plug-in type replaces current behaviour + +typedef void* (* _cmsMallocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void (* _cmsFreeFnPtrType)(cmsContext ContextID, void *Ptr); +typedef void* (* _cmsReallocFnPtrType)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + +typedef void* (* _cmsMalloZerocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void* (* _cmsCallocFnPtrType)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); +typedef void* (* _cmsDupFnPtrType)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + +typedef struct { + + cmsPluginBase base; + + // Required + _cmsMallocFnPtrType MallocPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; + + // Optional + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; + +} cmsPluginMemHandler; + + +// ------------------------------------------------------------------------------------------------------------------ + +// Interpolation. 16 bits and floating point versions. +struct _cms_interp_struc; + +// Interpolation callbacks + +// 16 bits forward interpolation. This function performs precision-limited linear interpolation +// and is supposed to be quite fast. Implementation may be tetrahedral or trilinear, and plug-ins may +// choose to implement any other interpolation algorithm. +typedef void (* _cmsInterpFn16)(CMSREGISTER const cmsUInt16Number Input[], + CMSREGISTER cmsUInt16Number Output[], + CMSREGISTER const struct _cms_interp_struc* p); + +// Floating point forward interpolation. Full precision interpolation using floats. This is not a +// time critical function. Implementation may be tetrahedral or trilinear, and plug-ins may +// choose to implement any other interpolation algorithm. +typedef void (* _cmsInterpFnFloat)(cmsFloat32Number const Input[], + cmsFloat32Number Output[], + const struct _cms_interp_struc* p); + + + +// This type holds a pointer to an interpolator that can be either 16 bits or float +typedef union { + _cmsInterpFn16 Lerp16; // Forward interpolation in 16 bits + _cmsInterpFnFloat LerpFloat; // Forward interpolation in floating point +} cmsInterpFunction; + +// Flags for interpolator selection +#define CMS_LERP_FLAGS_16BITS 0x0000 // The default +#define CMS_LERP_FLAGS_FLOAT 0x0001 // Requires different implementation +#define CMS_LERP_FLAGS_TRILINEAR 0x0100 // Hint only + + +#define MAX_INPUT_DIMENSIONS 15 + +typedef struct _cms_interp_struc { // Used on all interpolations. Supplied by lcms2 when calling the interpolation function + + cmsContext ContextID; // The calling thread + + cmsUInt32Number dwFlags; // Keep original flags + cmsUInt32Number nInputs; // != 1 only in 3D interpolation + cmsUInt32Number nOutputs; // != 1 only in 3D interpolation + + cmsUInt32Number nSamples[MAX_INPUT_DIMENSIONS]; // Valid on all kinds of tables + cmsUInt32Number Domain[MAX_INPUT_DIMENSIONS]; // Domain = nSamples - 1 + + cmsUInt32Number opta[MAX_INPUT_DIMENSIONS]; // Optimization for 3D CLUT. This is the number of nodes premultiplied for each + // dimension. For example, in 7 nodes, 7, 7^2 , 7^3, 7^4, etc. On non-regular + // Samplings may vary according of the number of nodes for each dimension. + + const void *Table; // Points to the actual interpolation table + cmsInterpFunction Interpolation; // Points to the function to do the interpolation + + } cmsInterpParams; + +// Interpolators factory +typedef cmsInterpFunction (* cmsInterpFnFactory)(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); + +// The plug-in +typedef struct { + cmsPluginBase base; + + // Points to a user-supplied function which implements the factory + cmsInterpFnFactory InterpolatorsFactory; + +} cmsPluginInterpolation; + +//---------------------------------------------------------------------------------------------------------- + +// Parametric curves. A negative type means same function but analytically inverted. Max. number of params is 10 + +// Evaluator callback for user-supplied parametric curves. May implement more than one type +typedef cmsFloat64Number (* cmsParametricCurveEvaluator)(cmsInt32Number Type, const cmsFloat64Number Params[10], cmsFloat64Number R); + +// Plug-in may implement an arbitrary number of parametric curves +typedef struct { + cmsPluginBase base; + + cmsUInt32Number nFunctions; // Number of supported functions + cmsUInt32Number FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types + cmsUInt32Number ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function + + cmsParametricCurveEvaluator Evaluator; // The evaluator + +} cmsPluginParametricCurves; +//---------------------------------------------------------------------------------------------------------- + +// Formatters. This plug-in adds new handlers, replacing them if they already exist. Formatters dealing with +// cmsFloat32Number (bps = 4) or double (bps = 0) types are requested via FormatterFloat callback. Others come across +// Formatter16 callback + +struct _cmstransform_struct; + +typedef cmsUInt8Number* (* cmsFormatter16)(CMSREGISTER struct _cmstransform_struct* CMMcargo, + CMSREGISTER cmsUInt16Number Values[], + CMSREGISTER cmsUInt8Number* Buffer, + CMSREGISTER cmsUInt32Number Stride); + +typedef cmsUInt8Number* (* cmsFormatterFloat)(struct _cmstransform_struct* CMMcargo, + cmsFloat32Number Values[], + cmsUInt8Number* Buffer, + cmsUInt32Number Stride); + +// This type holds a pointer to a formatter that can be either 16 bits or cmsFloat32Number +typedef union { + cmsFormatter16 Fmt16; + cmsFormatterFloat FmtFloat; + +} cmsFormatter; + +#define CMS_PACK_FLAGS_16BITS 0x0000 +#define CMS_PACK_FLAGS_FLOAT 0x0001 + +typedef enum { cmsFormatterInput=0, cmsFormatterOutput=1 } cmsFormatterDirection; + +typedef cmsFormatter (* cmsFormatterFactory)(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags); // precision + +// Plug-in may implement an arbitrary number of formatters +typedef struct { + cmsPluginBase base; + cmsFormatterFactory FormattersFactory; + +} cmsPluginFormatters; + +//---------------------------------------------------------------------------------------------------------- + +// Tag type handler. Each type is free to return anything it wants, and it is up to the caller to +// know in advance what is the type contained in the tag. +typedef struct _cms_typehandler_struct { + + cmsTagTypeSignature Signature; // The signature of the type + + // Allocates and reads items + void * (* ReadPtr)(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number* nItems, + cmsUInt32Number SizeOfTag); + + // Writes n Items + cmsBool (* WritePtr)(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Ptr, + cmsUInt32Number nItems); + + // Duplicate an item or array of items + void* (* DupPtr)(struct _cms_typehandler_struct* self, + const void *Ptr, + cmsUInt32Number n); + + // Free all resources + void (* FreePtr)(struct _cms_typehandler_struct* self, + void *Ptr); + + // Additional parameters used by the calling thread + cmsContext ContextID; + cmsUInt32Number ICCVersion; + +} cmsTagTypeHandler; + +// Each plug-in implements a single type +typedef struct { + cmsPluginBase base; + cmsTagTypeHandler Handler; + +} cmsPluginTagType; + +//---------------------------------------------------------------------------------------------------------- + +// This is the tag plugin, which identifies tags. For writing, a pointer to function is provided. +// This function should return the desired type for this tag, given the version of profile +// and the data being serialized. +typedef struct { + + cmsUInt32Number ElemCount; // If this tag needs an array, how many elements should keep + + // For reading. + cmsUInt32Number nSupportedTypes; // In how many types this tag can come (MAX_TYPES_IN_LCMS_PLUGIN maximum) + cmsTagTypeSignature SupportedTypes[MAX_TYPES_IN_LCMS_PLUGIN]; + + // For writing + cmsTagTypeSignature (* DecideType)(cmsFloat64Number ICCVersion, const void *Data); + +} cmsTagDescriptor; + +// Plug-in implements a single tag +typedef struct { + cmsPluginBase base; + + cmsTagSignature Signature; + cmsTagDescriptor Descriptor; + +} cmsPluginTag; + +//---------------------------------------------------------------------------------------------------------- + +// Custom intents. This function should join all profiles specified in the array in +// a single LUT. Any custom intent in the chain redirects to custom function. If more than +// one custom intent is found, the one located first is invoked. Usually users should use only one +// custom intent, so mixing custom intents in same multiprofile transform is not supported. + +typedef cmsPipeline* (* cmsIntentFn)( cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + + +// Each plug-in defines a single intent number. +typedef struct { + cmsPluginBase base; + cmsUInt32Number Intent; + cmsIntentFn Link; + char Description[256]; + +} cmsPluginRenderingIntent; + + +// The default ICC intents (perceptual, saturation, rel.col and abs.col) +CMSAPI cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags); + + +//---------------------------------------------------------------------------------------------------------- + +// Pipelines, Multi Process Elements. + +typedef void (* _cmsStageEvalFn) (const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage* mpe); +typedef void*(* _cmsStageDupElemFn) (cmsStage* mpe); +typedef void (* _cmsStageFreeElemFn) (cmsStage* mpe); + + +// This function allocates a generic MPE +CMSAPI cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, + cmsStageSignature Type, + cmsUInt32Number InputChannels, + cmsUInt32Number OutputChannels, + _cmsStageEvalFn EvalPtr, // Points to fn that evaluates the element (always in floating point) + _cmsStageDupElemFn DupElemPtr, // Points to a fn that duplicates the stage + _cmsStageFreeElemFn FreePtr, // Points to a fn that sets the element free + void* Data); // A generic pointer to whatever memory needed by the element +typedef struct { + cmsPluginBase base; + cmsTagTypeHandler Handler; + +} cmsPluginMultiProcessElement; + + +// Data kept in "Element" member of cmsStage + +// Curves +typedef struct { + cmsUInt32Number nCurves; + cmsToneCurve** TheCurves; + +} _cmsStageToneCurvesData; + +// Matrix +typedef struct { + cmsFloat64Number* Double; // floating point for the matrix + cmsFloat64Number* Offset; // The offset + +} _cmsStageMatrixData; + +// CLUT +typedef struct { + + union { // Can have only one of both representations at same time + cmsUInt16Number* T; // Points to the table 16 bits table + cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table + + } Tab; + + cmsInterpParams* Params; + cmsUInt32Number nEntries; + cmsBool HasFloatValues; + +} _cmsStageCLutData; + + +//---------------------------------------------------------------------------------------------------------- +// Optimization. Using this plug-in, additional optimization strategies may be implemented. +// The function should return TRUE if any optimization is done on the LUT, this terminates +// the optimization search. Or FALSE if it is unable to optimize and want to give a chance +// to the rest of optimizers. + +typedef cmsBool (* _cmsOPToptimizeFn)(cmsPipeline** Lut, + cmsUInt32Number Intent, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags); + +// Pipeline Evaluator (in 16 bits) +typedef void (* _cmsPipelineEval16Fn)(CMSREGISTER const cmsUInt16Number In[], + CMSREGISTER cmsUInt16Number Out[], + const void* Data); + +// Pipeline Evaluator (in floating point) +typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const void* Data); + + +// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional +// duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. + +CMSAPI void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, + _cmsPipelineEval16Fn Eval16, + void* PrivateData, + _cmsFreeUserDataFn FreePrivateDataFn, + _cmsDupUserDataFn DupPrivateDataFn); + +typedef struct { + cmsPluginBase base; + + // Optimize entry point + _cmsOPToptimizeFn OptimizePtr; + +} cmsPluginOptimization; + +//---------------------------------------------------------------------------------------------------------- +// Full xform + +typedef struct { + cmsUInt32Number BytesPerLineIn; + cmsUInt32Number BytesPerLineOut; + cmsUInt32Number BytesPerPlaneIn; + cmsUInt32Number BytesPerPlaneOut; + +} cmsStride; + +typedef void (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo, // Legacy function, handles just ONE scanline. + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size, + cmsUInt32Number Stride); // Stride in bytes to the next plana in planar formats + + +typedef void (*_cmsTransform2Fn)(struct _cmstransform_struct *CMMcargo, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride); + +typedef cmsBool (* _cmsTransformFactory)(_cmsTransformFn* xform, + void** UserData, + _cmsFreeUserDataFn* FreePrivateDataFn, + cmsPipeline** Lut, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags); + +typedef cmsBool (* _cmsTransform2Factory)(_cmsTransform2Fn* xform, + void** UserData, + _cmsFreeUserDataFn* FreePrivateDataFn, + cmsPipeline** Lut, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags); + + +// Retrieve user data as specified by the factory +CMSAPI void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn); +CMSAPI void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo); + + +// Retrieve formatters +CMSAPI void CMSEXPORT _cmsGetTransformFormatters16 (struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput); +CMSAPI void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput); + +// Retrieve original flags +CMSAPI cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMMcargo); + +typedef struct { + cmsPluginBase base; + + // Transform entry point + union { + _cmsTransformFactory legacy_xform; + _cmsTransform2Factory xform; + } factories; + +} cmsPluginTransform; + +//---------------------------------------------------------------------------------------------------------- +// Mutex + +typedef void* (* _cmsCreateMutexFnPtrType)(cmsContext ContextID); +typedef void (* _cmsDestroyMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef cmsBool (* _cmsLockMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef void (* _cmsUnlockMutexFnPtrType)(cmsContext ContextID, void* mtx); + +typedef struct { + cmsPluginBase base; + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} cmsPluginMutex; + +CMSAPI void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID); +CMSAPI void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx); +CMSAPI cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx); +CMSAPI void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx); + + +#ifndef CMS_USE_CPP_API +# ifdef __cplusplus + } +# endif +#endif + +#define _lcms_plugin_H +#endif diff -Nru openjdk-17-17.0.3+7/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java openjdk-17-17.0.4+8/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java --- openjdk-17-17.0.3+7/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -294,6 +294,12 @@ return null; } + private String extractOsInfo(String s) { + if (s.startsWith("\"")) s = s.substring(1); + if (s.endsWith("\"")) s = s.substring(0, s.length()-1); + return s; + } + /** * Sets the OS name and version from environment information. */ @@ -328,6 +334,16 @@ } else if ((f = new File("/etc/fedora-release")).canRead()) { osName = "Fedora"; osVersion = getVersionString(f); + } else if ((f = new File("/etc/os-release")).canRead()) { + Properties props = new Properties(); + try (FileInputStream fis = new FileInputStream(f)) { + props.load(fis); + } + osName = props.getProperty("NAME"); + osVersion = props.getProperty("VERSION_ID"); + osName = extractOsInfo(osName); + if (osName.equals("SLES")) osName = "SuSE"; + osVersion = extractOsInfo(osVersion); } } catch (Exception e) { if (FontUtilities.debugFonts()) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java openjdk-17-17.0.4+8/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java --- openjdk-17-17.0.3+7/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,6 +112,16 @@ props.load(new FileInputStream(f)); osName = props.getProperty("DISTRIB_ID"); osVersion = props.getProperty("DISTRIB_RELEASE"); + } else if ((f = new File("/etc/os-release")).canRead()) { + Properties props = new Properties(); + try (FileInputStream fis = new FileInputStream(f)) { + props.load(fis); + } + osName = props.getProperty("NAME"); + osVersion = props.getProperty("VERSION_ID"); + osName = extractOsInfo(osName); + if (osName.equals("SLES")) osName = "SuSE"; + osVersion = extractOsInfo(osVersion); } } catch (Exception e) { } @@ -132,6 +142,12 @@ return null; } + private String extractOsInfo(String s) { + if (s.startsWith("\"")) s = s.substring(1); + if (s.endsWith("\"")) s = s.substring(0, s.length()-1); + return s; + } + private static final String fontsDirPrefix = "$JRE_LIB_FONTS"; protected String mapFileName(String fileName) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java openjdk-17-17.0.4+8/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java --- openjdk-17-17.0.3+7/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java 2022-07-14 08:05:38.000000000 +0000 @@ -54,6 +54,7 @@ private static native String getCupsServer(); private static native int getCupsPort(); private static native String getCupsDefaultPrinter(); + private static native String[] getCupsDefaultPrinters(); private static native boolean canConnect(String server, int port); private static native boolean initIDs(); // These functions need to be synchronized as @@ -78,6 +79,7 @@ private static boolean libFound; private static String cupsServer = null; + private static String domainSocketPathname = null; private static int cupsPort = 0; static { @@ -92,6 +94,13 @@ libFound = initIDs(); if (libFound) { cupsServer = getCupsServer(); + // Is this a local domain socket pathname? + if (cupsServer != null && cupsServer.startsWith("/")) { + if (isSandboxedApp()) { + domainSocketPathname = cupsServer; + } + cupsServer = "localhost"; + } cupsPort = getCupsPort(); } } @@ -376,6 +385,20 @@ * Get list of all CUPS printers using IPP. */ static String[] getAllPrinters() { + + if (getDomainSocketPathname() != null) { + String[] printerNames = getCupsDefaultPrinters(); + if (printerNames != null && printerNames.length > 0) { + String[] printerURIs = new String[printerNames.length]; + for (int i=0; i< printerNames.length; i++) { + printerURIs[i] = String.format("ipp://%s:%d/printers/%s", + getServer(), getPort(), printerNames[i]); + } + return printerURIs; + } + return null; + } + try { URL url = new URL("http", getServer(), getPort(), ""); @@ -459,14 +482,38 @@ } /** + * Returns CUPS domain socket pathname. + */ + private static String getDomainSocketPathname() { + return domainSocketPathname; + } + + @SuppressWarnings("removal") + private static boolean isSandboxedApp() { + if (PrintServiceLookupProvider.isMac()) { + return java.security.AccessController + .doPrivileged((java.security.PrivilegedAction) () -> + System.getenv("APP_SANDBOX_CONTAINER_ID") != null); + } + return false; + } + + + /** * Detects if CUPS is running. */ public static boolean isCupsRunning() { IPPPrintService.debug_println(debugPrefix+"libFound "+libFound); if (libFound) { - IPPPrintService.debug_println(debugPrefix+"CUPS server "+getServer()+ - " port "+getPort()); - return canConnect(getServer(), getPort()); + String server = getDomainSocketPathname() != null + ? getDomainSocketPathname() + : getServer(); + IPPPrintService.debug_println(debugPrefix+"CUPS server "+server+ + " port "+getPort()+ + (getDomainSocketPathname() != null + ? " use domain socket pathname" + : "")); + return canConnect(server, getPort()); } else { return false; } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/unix/native/common/awt/colordata.h openjdk-17-17.0.4+8/src/java.desktop/unix/native/common/awt/colordata.h --- openjdk-17-17.0.3+7/src/java.desktop/unix/native/common/awt/colordata.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/unix/native/common/awt/colordata.h 2022-07-14 08:05:38.000000000 +0000 @@ -39,9 +39,9 @@ unsigned char *awt_icmLUT2Colors; unsigned char *img_grays; unsigned char *img_clr_tbl; - char* img_oda_red; - char* img_oda_green; - char* img_oda_blue; + signed char* img_oda_red; + signed char* img_oda_green; + signed char* img_oda_blue; int *pGrayInverseLutData; int screendata; int representsPrimaries; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/unix/native/common/awt/CUPSfuncs.c openjdk-17-17.0.4+8/src/java.desktop/unix/native/common/awt/CUPSfuncs.c --- openjdk-17-17.0.3+7/src/java.desktop/unix/native/common/awt/CUPSfuncs.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/unix/native/common/awt/CUPSfuncs.c 2022-07-14 08:05:38.000000000 +0000 @@ -172,12 +172,7 @@ jstring cServer = NULL; const char* server = j2d_cupsServer(); if (server != NULL) { - // Is this a local domain socket? - if (strncmp(server, "/", 1) == 0) { - cServer = JNU_NewStringPlatform(env, "localhost"); - } else { - cServer = JNU_NewStringPlatform(env, server); - } + cServer = JNU_NewStringPlatform(env, server); } return cServer; } @@ -220,6 +215,58 @@ } /* + * Returns list of default local printers + */ +JNIEXPORT jobjectArray JNICALL +Java_sun_print_CUPSPrinter_getCupsDefaultPrinters(JNIEnv *env, + jobject printObj) +{ + cups_dest_t *dests; + int i, j, num_dests; + jstring utf_str; + jclass cls; + jobjectArray nameArray = NULL; + + cls = (*env)->FindClass(env, "java/lang/String"); + CHECK_NULL_RETURN(cls, NULL); + + num_dests = j2d_cupsGetDests(&dests); + + if (dests == NULL) { + return NULL; + } + + nameArray = (*env)->NewObjectArray(env, num_dests, cls, NULL); + if (nameArray == NULL) { + j2d_cupsFreeDests(num_dests, dests); + DPRINTF("CUPSfuncs::bad alloc new array\n", "") + return NULL; + } + + for (i = 0; i < num_dests; i++) { + utf_str = JNU_NewStringPlatform(env, dests[i].name); + if (utf_str == NULL) { + (*env)->ExceptionClear(env); + for (j = i - 1; j >= 0; j--) { + utf_str = (*env)->GetObjectArrayElement(env, nameArray, j); + (*env)->SetObjectArrayElement(env, nameArray, j, NULL); + (*env)->DeleteLocalRef(env, utf_str); + utf_str = NULL; + } + j2d_cupsFreeDests(num_dests, dests); + (*env)->DeleteLocalRef(env, nameArray); + DPRINTF("CUPSfuncs::bad alloc new string ->name\n", "") + return NULL; + } + (*env)->SetObjectArrayElement(env, nameArray, i, utf_str); + (*env)->DeleteLocalRef(env, utf_str); + } + + j2d_cupsFreeDests(num_dests, dests); + return nameArray; +} + +/* * Checks if connection can be made to the server. * */ @@ -299,8 +346,9 @@ unlink(filename); j2d_ppdClose(ppd); DPRINTF("CUPSfuncs::bad alloc new array\n", "") - (*env)->ExceptionClear(env); - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + if (!(*env)->ExceptionCheck(env)) { + JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + } return NULL; } @@ -311,7 +359,9 @@ unlink(filename); j2d_ppdClose(ppd); DPRINTF("CUPSfuncs::bad alloc new string ->text\n", "") - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + if (!(*env)->ExceptionCheck(env)) { + JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + } return NULL; } (*env)->SetObjectArrayElement(env, nameArray, i*2, utf_str); @@ -321,7 +371,9 @@ unlink(filename); j2d_ppdClose(ppd); DPRINTF("CUPSfuncs::bad alloc new string ->choice\n", "") - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + if (!(*env)->ExceptionCheck(env)) { + JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + } return NULL; } (*env)->SetObjectArrayElement(env, nameArray, i*2+1, utf_str); @@ -335,7 +387,9 @@ unlink(filename); j2d_ppdClose(ppd); DPRINTF("CUPSfuncs::bad alloc new string text\n", "") - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + if (!(*env)->ExceptionCheck(env)) { + JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + } return NULL; } (*env)->SetObjectArrayElement(env, nameArray, @@ -346,7 +400,9 @@ unlink(filename); j2d_ppdClose(ppd); DPRINTF("CUPSfuncs::bad alloc new string choice\n", "") - JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + if (!(*env)->ExceptionCheck(env)) { + JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); + } return NULL; } (*env)->SetObjectArrayElement(env, nameArray, diff -Nru openjdk-17-17.0.3+7/src/java.desktop/unix/native/common/awt/fontpath.c openjdk-17-17.0.4+8/src/java.desktop/unix/native/common/awt/fontpath.c --- openjdk-17-17.0.3+7/src/java.desktop/unix/native/common/awt/fontpath.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/unix/native/common/awt/fontpath.c 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -496,6 +496,7 @@ FcChar8 ** s); typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file); typedef void (*FcPatternDestroyFuncType)(FcPattern *p); +typedef void (*FcObjectSetDestroyFuncType)(FcObjectSet *os); typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s); typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name); typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p, @@ -542,6 +543,7 @@ FcPatternGetStringFuncType FcPatternGetString; FcStrDirnameFuncType FcStrDirname; FcPatternDestroyFuncType FcPatternDestroy; + FcObjectSetDestroyFuncType FcObjectSetDestroy; FcFontSetDestroyFuncType FcFontSetDestroy; FcConfig *fontconfig; @@ -571,6 +573,8 @@ (FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname"); FcPatternDestroy = (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy"); + FcObjectSetDestroy = + (FcObjectSetDestroyFuncType)dlsym(libfontconfig, "FcObjectSetDestroy"); FcFontSetDestroy = (FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy"); @@ -580,6 +584,7 @@ FcFontList == NULL || FcStrDirname == NULL || FcPatternDestroy == NULL || + FcObjectSetDestroy == NULL || FcFontSetDestroy == NULL) { /* problem with the library: return. */ closeFontConfig(libfontconfig, JNI_FALSE); return NULL; @@ -636,6 +641,7 @@ cleanup: /* Free memory and close the ".so" */ + (*FcObjectSetDestroy)(objset); (*FcPatternDestroy)(pattern); closeFontConfig(libfontconfig, JNI_TRUE); return fontdirs; @@ -935,8 +941,10 @@ if (cacheDirs != NULL) { while ((cnt < max) && (cacheDir = (*FcStrListNext)(cacheDirs))) { jstr = (*env)->NewStringUTF(env, (const char*)cacheDir); - JNU_CHECK_EXCEPTION(env); - + if (IS_NULL(jstr)) { + (*FcStrListDone)(cacheDirs); + return; + } (*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr); (*env)->DeleteLocalRef(env, jstr); } diff -Nru openjdk-17-17.0.3+7/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c openjdk-17-17.0.4+8/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c --- openjdk-17-17.0.3+7/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -579,7 +579,8 @@ XFree (pVI8sg); if (n1sg != 0) XFree (pVI1sg); - + if (nTrue != 0) + XFree (pVITrue); AWT_UNLOCK (); } @@ -1428,6 +1429,9 @@ break; } } + AWT_LOCK(); + XdbeFreeVisualInfo(visScreenInfo); + AWT_UNLOCK(); } /* diff -Nru openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp --- openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3917,11 +3917,11 @@ HIMC hIMC = ImmGetContext(hwnd); if (hIMC) { CANDIDATEFORM cf; - cf.dwStyle = CFS_POINT; + cf.dwStyle = CFS_CANDIDATEPOS; ImmGetCandidateWindow(hIMC, 0, &cf); if (x != cf.ptCurrentPos.x || y != cf.ptCurrentPos.y) { cf.dwIndex = iCandType; - cf.dwStyle = CFS_POINT; + cf.dwStyle = CFS_CANDIDATEPOS; cf.ptCurrentPos = {x, y}; cf.rcArea = {0, 0, 0, 0}; ImmSetCandidateWindow(hIMC, &cf); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp --- openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -267,13 +267,13 @@ dragSource->Signal(); AwtToolkit &toolkit = AwtToolkit::GetInstance(); - toolkit.isInDoDragDropLoop = TRUE; + toolkit.isDnDSourceActive = TRUE; res = ::DoDragDrop(dragSource, dragSource, convertActionsToDROPEFFECT(dragSource->m_actions), &effects ); - toolkit.isInDoDragDropLoop = FALSE; + toolkit.isDnDSourceActive = FALSE; if (effects == DROPEFFECT_NONE && dragSource->m_dwPerformedDropEffect != DROPEFFECT_NONE) { effects = dragSource->m_dwPerformedDropEffect; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_DnDDT.cpp openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_DnDDT.cpp --- openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_DnDDT.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_DnDDT.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,7 +141,7 @@ HRESULT __stdcall AwtDropTarget::DragEnter(IDataObject __RPC_FAR *pDataObj, DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect) { TRY; - AwtToolkit::GetInstance().isInDoDragDropLoop = TRUE; + AwtToolkit::GetInstance().isDnDTargetActive = TRUE; if (NULL != m_pIDropTargetHelper) { m_pIDropTargetHelper->DragEnter( m_window, @@ -161,7 +161,7 @@ (IsLocalDnD() && !IsLocalDataObject(pDataObj))) { *pdwEffect = retEffect; - AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE; + AwtToolkit::GetInstance().isDnDTargetActive = FALSE; return ret; } @@ -173,7 +173,7 @@ } if (JNU_IsNull(env, m_dtcp) || !JNU_IsNull(env, safe_ExceptionOccurred(env))) { - AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE; + AwtToolkit::GetInstance().isDnDTargetActive = FALSE; return ret; } @@ -200,12 +200,12 @@ env->ExceptionDescribe(); env->ExceptionClear(); actions = java_awt_dnd_DnDConstants_ACTION_NONE; - AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE; + AwtToolkit::GetInstance().isDnDTargetActive = FALSE; } } catch (std::bad_alloc&) { retEffect = ::convertActionsToDROPEFFECT(actions); *pdwEffect = retEffect; - AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE; + AwtToolkit::GetInstance().isDnDTargetActive = FALSE; throw; } @@ -421,7 +421,7 @@ m_dropSuccess = success; m_dropActions = action; AwtToolkit::GetInstance().QuitMessageLoop(AwtToolkit::EXIT_ENCLOSING_LOOP); - AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE; + AwtToolkit::GetInstance().isDnDTargetActive = FALSE; } /** @@ -1136,7 +1136,7 @@ void AwtDropTarget::DragCleanup(void) { UnloadCache(); - AwtToolkit::GetInstance().isInDoDragDropLoop = FALSE; + AwtToolkit::GetInstance().isDnDTargetActive = FALSE; } BOOL AwtDropTarget::IsLocalDataObject(IDataObject __RPC_FAR *pDataObject) { diff -Nru openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp --- openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -28,20 +28,33 @@ #include "awt_Component.h" #include -static int signum(int i) { - // special version of signum which returns 1 when value is 0 - return i >= 0 ? 1 : -1; -} - static void MouseMove(jint x, jint y) { INPUT mouseInput = {0}; mouseInput.type = INPUT_MOUSE; mouseInput.mi.time = 0; - mouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - mouseInput.mi.dx = (x * 65536 /::GetSystemMetrics(SM_CXSCREEN)) + signum(x); - mouseInput.mi.dy = (y * 65536 /::GetSystemMetrics(SM_CYSCREEN)) + signum(y); + + // The following calculations take into account a multi-monitor setup using + // a virtual screen for all monitors combined. + // More details from Microsoft are here -- + // https://docs.microsoft.com/en-us/windows/win32/gdi/the-virtual-screen + + x -= ::GetSystemMetrics(SM_XVIRTUALSCREEN); + y -= ::GetSystemMetrics(SM_YVIRTUALSCREEN); + + mouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | + MOUSEEVENTF_VIRTUALDESK; + + int scW = ::GetSystemMetrics(SM_CXVIRTUALSCREEN); + int scH = ::GetSystemMetrics(SM_CYVIRTUALSCREEN); + + // The following calculation to deduce mouse coordinates is based on + // empirical data + mouseInput.mi.dx = (x * 65536 + scW - 1) / scW; + mouseInput.mi.dy = (y * 65536 + scH - 1) / scH; + ::SendInput(1, &mouseInput, sizeof(mouseInput)); + } static void MousePress(jint buttonMask) diff -Nru openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp --- openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -344,7 +344,8 @@ m_waitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); m_inputMethodWaitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); - isInDoDragDropLoop = FALSE; + isDnDSourceActive = FALSE; + isDnDTargetActive = FALSE; eventNumber = 0; } @@ -3012,7 +3013,7 @@ tk.PostMessage(WM_SYNC_WAIT, 0, 0); for(long t = 2; t < timeout && WAIT_TIMEOUT == ::WaitForSingleObject(tk.m_waitEvent, 2); t+=2) { - if (tk.isInDoDragDropLoop) { + if (tk.isDnDSourceActive || tk.isDnDTargetActive) { break; } } @@ -3216,7 +3217,7 @@ * the IME completion. */ CriticalSection::Lock lock(m_inputMethodLock); - if (isInDoDragDropLoop) { + if (isDnDSourceActive || isDnDTargetActive) { SendMessage(msg, wParam, lParam); ::ResetEvent(m_inputMethodWaitEvent); return m_inputMethodData; diff -Nru openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h --- openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -441,7 +441,8 @@ HANDLE m_waitEvent; volatile DWORD eventNumber; - volatile BOOL isInDoDragDropLoop; + volatile BOOL isDnDSourceActive; + volatile BOOL isDnDTargetActive; private: HWND CreateToolkitWnd(LPCTSTR name); diff -Nru openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/colordata.h openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/colordata.h --- openjdk-17-17.0.3+7/src/java.desktop/windows/native/libawt/windows/colordata.h 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.desktop/windows/native/libawt/windows/colordata.h 2022-07-14 08:05:38.000000000 +0000 @@ -28,9 +28,9 @@ #include "img_globals.h" typedef struct _ColorData { - char* img_oda_red; - char* img_oda_green; - char* img_oda_blue; + signed char* img_oda_red; + signed char* img_oda_green; + signed char* img_oda_blue; unsigned char* img_clr_tbl; int *pGrayInverseLutData; int representsPrimaries; diff -Nru openjdk-17-17.0.3+7/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/LdapSasl.java openjdk-17-17.0.4+8/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/LdapSasl.java --- openjdk-17-17.0.3+7/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/LdapSasl.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/LdapSasl.java 2022-07-14 08:05:38.000000000 +0000 @@ -42,7 +42,9 @@ import com.sun.jndi.ldap.Connection; import com.sun.jndi.ldap.LdapClient; import com.sun.jndi.ldap.LdapResult; -import com.sun.jndi.ldap.sasl.TlsChannelBinding.TlsChannelBindingType; +import sun.security.util.ChannelBindingException; +import sun.security.util.TlsChannelBinding; +import sun.security.util.TlsChannelBinding.TlsChannelBindingType; /** * Handles SASL support. @@ -62,6 +64,14 @@ private static final int LDAP_SUCCESS = 0; private static final int LDAP_SASL_BIND_IN_PROGRESS = 14; // LDAPv3 + // TLS channel binding type property + private static final String CHANNEL_BINDING_TYPE = + "com.sun.jndi.ldap.tls.cbtype"; + + // internal TLS channel binding property + private static final String CHANNEL_BINDING = + "jdk.internal.sasl.tlschannelbinding"; + private LdapSasl() { } @@ -113,8 +123,8 @@ String[] mechs = getSaslMechanismNames(authMech); // Internal TLS Channel Binding property cannot be set explicitly - if (env.get(TlsChannelBinding.CHANNEL_BINDING) != null) { - throw new NamingException(TlsChannelBinding.CHANNEL_BINDING + + if (env.get(CHANNEL_BINDING) != null) { + throw new NamingException(CHANNEL_BINDING + " property cannot be set explicitly"); } @@ -123,17 +133,24 @@ try { // Prepare TLS Channel Binding data if (conn.isTlsConnection()) { - TlsChannelBindingType cbType = - TlsChannelBinding.parseType( - (String)env.get(TlsChannelBinding.CHANNEL_BINDING_TYPE)); + TlsChannelBindingType cbType; + try { + cbType = TlsChannelBinding.parseType((String)env.get(CHANNEL_BINDING_TYPE)); + } catch (ChannelBindingException e) { + throw wrapInNamingException(e); + } if (cbType == TlsChannelBindingType.TLS_SERVER_END_POINT) { // set tls-server-end-point channel binding X509Certificate cert = conn.getTlsServerCertificate(); if (cert != null) { - TlsChannelBinding tlsCB = - TlsChannelBinding.create(cert); + TlsChannelBinding tlsCB; + try { + tlsCB = TlsChannelBinding.create(cert); + } catch (ChannelBindingException e) { + throw wrapInNamingException(e); + } envProps = (Hashtable) env.clone(); - envProps.put(TlsChannelBinding.CHANNEL_BINDING, tlsCB.getData()); + envProps.put(CHANNEL_BINDING, tlsCB.getData()); } else { throw new SaslException("No suitable certificate to generate " + "TLS Channel Binding data"); @@ -227,5 +244,11 @@ return mechNames; } + private static NamingException wrapInNamingException(Exception e) { + NamingException ne = new NamingException(); + ne.setRootCause(e); + return ne; + } + private static final byte[] NO_BYTES = new byte[0]; } diff -Nru openjdk-17-17.0.3+7/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/TlsChannelBinding.java openjdk-17-17.0.4+8/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/TlsChannelBinding.java --- openjdk-17-17.0.3+7/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/TlsChannelBinding.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.naming/share/classes/com/sun/jndi/ldap/sasl/TlsChannelBinding.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 com.sun.jndi.ldap.sasl; - -import javax.naming.NamingException; -import javax.security.sasl.SaslException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Hashtable; - -/** - * This class implements the Channel Binding for TLS as defined in - * - * Channel Bindings for TLS - * - * Format of the Channel Binding data is also defined in - * - * On the Use of Channel Bindings to Secure Channels - * section 2.1. - * - */ - -public class TlsChannelBinding { - - // TLS channel binding type property - public static final String CHANNEL_BINDING_TYPE = - "com.sun.jndi.ldap.tls.cbtype"; - - // internal TLS channel binding property - public static final String CHANNEL_BINDING = - "jdk.internal.sasl.tlschannelbinding"; - - public enum TlsChannelBindingType { - - /** - * Channel binding on the basis of TLS Finished message. - * TLS_UNIQUE is defined by RFC 5929 but is not supported - * by the current LDAP stack. - */ - TLS_UNIQUE("tls-unique"), - - /** - * Channel binding on the basis of TLS server certificate. - */ - TLS_SERVER_END_POINT("tls-server-end-point"); - - public String getName() { - return name; - } - - private final String name; - TlsChannelBindingType(String name) { - this.name = name; - } - } - - /** - * Parse value of "com.sun.jndi.ldap.tls.cbtype" property - * @param cbType - * @return TLS Channel Binding type or null if - * "com.sun.jndi.ldap.tls.cbtype" property has not been set. - * @throws NamingException - */ - public static TlsChannelBindingType parseType(String cbType) throws NamingException { - if (cbType != null) { - if (cbType.equals(TlsChannelBindingType.TLS_SERVER_END_POINT.getName())) { - return TlsChannelBindingType.TLS_SERVER_END_POINT; - } else { - throw new NamingException("Illegal value for " + - CHANNEL_BINDING_TYPE + " property."); - } - } - return null; - } - - private final TlsChannelBindingType cbType; - private final byte[] cbData; - - /** - * Construct tls-server-end-point Channel Binding data - * @param serverCertificate - * @throws SaslException - */ - public static TlsChannelBinding create(X509Certificate serverCertificate) throws SaslException { - try { - final byte[] prefix = - TlsChannelBindingType.TLS_SERVER_END_POINT.getName().concat(":").getBytes(); - String hashAlg = serverCertificate.getSigAlgName(). - replace("SHA", "SHA-").toUpperCase(); - int ind = hashAlg.indexOf("WITH"); - if (ind > 0) { - hashAlg = hashAlg.substring(0, ind); - if (hashAlg.equals("MD5") || hashAlg.equals("SHA-1")) { - hashAlg = "SHA-256"; - } - } else { - hashAlg = "SHA-256"; - } - MessageDigest md = MessageDigest.getInstance(hashAlg); - byte[] hash = md.digest(serverCertificate.getEncoded()); - byte[] cbData = Arrays.copyOf(prefix, prefix.length + hash.length ); - System.arraycopy(hash, 0, cbData, prefix.length, hash.length); - return new TlsChannelBinding(TlsChannelBindingType.TLS_SERVER_END_POINT, cbData); - } catch (NoSuchAlgorithmException | CertificateEncodingException e) { - throw new SaslException("Cannot create TLS channel binding data", e); - } - } - - private TlsChannelBinding(TlsChannelBindingType cbType, byte[] cbData) { - this.cbType = cbType; - this.cbData = cbData; - } - - public TlsChannelBindingType getType() { - return cbType; - } - - public byte[] getData() { - return cbData; - } -} diff -Nru openjdk-17-17.0.3+7/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java openjdk-17-17.0.4+8/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java --- openjdk-17-17.0.3+7/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java 2022-07-14 08:05:38.000000000 +0000 @@ -40,6 +40,9 @@ import sun.security.jgss.GSSContextImpl; import sun.security.jgss.GSSUtil; import sun.security.jgss.HttpCaller; +import sun.security.jgss.krb5.internal.TlsChannelBindingImpl; +import sun.security.util.ChannelBindingException; +import sun.security.util.TlsChannelBinding; /** * This class encapsulates all JAAS and JGSS API calls in a separate class @@ -65,7 +68,7 @@ *
  • Creating GSSContext *
  • A first call to initSecContext */ - private void init(HttpCallerInfo hci) throws GSSException { + private void init(HttpCallerInfo hci) throws GSSException, ChannelBindingException { final Oid oid; if (hci.scheme.equalsIgnoreCase("Kerberos")) { @@ -100,6 +103,14 @@ if (context instanceof GSSContextImpl) { ((GSSContextImpl)context).requestDelegPolicy(true); } + if (hci.serverCert != null) { + if (DEBUG) { + System.out.println("Negotiate: Setting CBT"); + } + // set the channel binding token + TlsChannelBinding b = TlsChannelBinding.create(hci.serverCert); + context.setChannelBinding(new TlsChannelBindingImpl(b.getData())); + } oneToken = context.initSecContext(new byte[0], 0, 0); } @@ -110,7 +121,7 @@ public NegotiatorImpl(HttpCallerInfo hci) throws IOException { try { init(hci); - } catch (GSSException e) { + } catch (GSSException | ChannelBindingException e) { if (DEBUG) { System.out.println("Negotiate support not initiated, will " + "fallback to other scheme if allowed. Reason:"); diff -Nru openjdk-17-17.0.3+7/src/java.security.jgss/share/classes/sun/security/jgss/spnego/SpNegoContext.java openjdk-17-17.0.4+8/src/java.security.jgss/share/classes/sun/security/jgss/spnego/SpNegoContext.java --- openjdk-17-17.0.3+7/src/java.security.jgss/share/classes/sun/security/jgss/spnego/SpNegoContext.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.security.jgss/share/classes/sun/security/jgss/spnego/SpNegoContext.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -866,6 +866,7 @@ mechContext.requestMutualAuth(mutualAuthState); mechContext.requestReplayDet(replayDetState); mechContext.requestSequenceDet(sequenceDetState); + mechContext.setChannelBinding(channelBinding); if (mechContext instanceof GSSContextImpl) { ((GSSContextImpl)mechContext).requestDelegPolicy( delegPolicyState); @@ -899,6 +900,7 @@ myCred.getInternalCred()); } mechContext = factory.manager.createContext(cred); + mechContext.setChannelBinding(channelBinding); } // pass token to mechanism acceptSecContext diff -Nru openjdk-17-17.0.3+7/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp openjdk-17-17.0.4+8/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp --- openjdk-17-17.0.3+7/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1043,6 +1043,10 @@ { PP(">>>> Calling UNIMPLEMENTED gss_accept_sec_context..."); PP("gss_accept_sec_context is not supported in this initiator-only library"); + if (output_token) { + output_token->length = 0; + output_token->value = NULL; + } return GSS_S_FAILURE; } diff -Nru openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java --- openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,6 +25,7 @@ import java.io.IOException; import com.sun.org.apache.bcel.internal.Const; +import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; /** * This class represents the constant pool, i.e., a table of constants, of @@ -37,6 +37,7 @@ * @see Constant * @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen + * @LastModified: May 2022 */ public class ConstantPool implements Cloneable, Node { @@ -222,8 +223,16 @@ * @throws IOException */ public void dump( final DataOutputStream file ) throws IOException { - file.writeShort(constantPool.length); - for (int i = 1; i < constantPool.length; i++) { + /* + * Constants over the size of the constant pool shall not be written out. + * This is a redundant measure as the ConstantPoolGen should have already + * reported an error back in the situation. + */ + int size = constantPool.length < ConstantPoolGen.CONSTANT_POOL_SIZE - 1 ? + constantPool.length : ConstantPoolGen.CONSTANT_POOL_SIZE - 1; + + file.writeShort(size); + for (int i = 1; i < size; i++) { if (constantPool[i] != null) { constantPool[i].dump(file); } diff -Nru openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ConstantPoolGen.java openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ConstantPoolGen.java --- openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ConstantPoolGen.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ConstantPoolGen.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -50,10 +50,10 @@ * JVM and that Double and Long constants need two slots. * * @see Constant - * @LastModified: May 2021 + * @LastModified: May 2022 */ public class ConstantPoolGen { - + public static final int CONSTANT_POOL_SIZE = 65536; private static final int DEFAULT_BUFFER_SIZE = 256; private int size; private Constant[] constants; @@ -83,7 +83,7 @@ public ConstantPoolGen(final Constant[] cs) { final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE); - size = Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64); + size = Math.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), CONSTANT_POOL_SIZE); constants = new Constant[size]; System.arraycopy(cs, 0, constants, 0, cs.length); @@ -212,9 +212,18 @@ /** Resize internal array of constants. */ protected void adjustSize() { + // 3 extra spaces are needed as some entries may take 3 slots + if (index + 3 >= CONSTANT_POOL_SIZE) { + throw new RuntimeException("The number of constants " + (index + 3) + + " is over the size of the constant pool: " + + (CONSTANT_POOL_SIZE - 1)); + } + if (index + 3 >= size) { final Constant[] cs = constants; size *= 2; + // the constant array shall not exceed the size of the constant pool + size = Math.min(size, CONSTANT_POOL_SIZE); constants = new Constant[size]; System.arraycopy(cs, 0, constants, 0, index); } diff -Nru openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java --- openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java 2022-07-14 08:05:38.000000000 +0000 @@ -459,8 +459,11 @@ if (name != null) { setClassName(name); } - else if (systemId != null && !systemId.equals("")) { - setClassName(Util.baseName(systemId)); + else if (systemId != null && !systemId.isEmpty()) { + String clsName = Util.baseName(systemId); + if (clsName != null && !clsName.isEmpty()) { + setClassName(clsName); + } } // Ensure we have a non-empty class name at this point diff -Nru openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Lexer.java openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Lexer.java --- openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Lexer.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Lexer.java 2022-07-14 08:05:38.000000000 +0000 @@ -32,7 +32,7 @@ * This class is in charge of lexical processing of the XPath * expression into tokens. * - * @LastModified: Jan 2022 + * @LastModified: Apr 2022 */ class Lexer { @@ -360,7 +360,7 @@ addToTokenQueue(pat.substring(i, i + 1)); break; - case Token.COLON_CHAR: + case Token.COLON : if (i>0) { if (posOfNSSep == (i - 1)) @@ -615,7 +615,7 @@ resetTokenMark(tokPos + 1); } - if (m_processor.lookahead(Token.COLON_CHAR, 1)) + if (m_processor.lookahead(Token.COLON, 1)) { tokPos += 2; } diff -Nru openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Token.java openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Token.java --- openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Token.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/Token.java 2022-07-14 08:05:38.000000000 +0000 @@ -45,9 +45,10 @@ static final char LPAREN = '('; static final char RPAREN = ')'; static final char COMMA = ','; + static final char DOT = '.'; static final char AT = '@'; static final char US = '_'; - static final char COLON_CHAR = ':'; + static final char COLON = ':'; static final char SQ = '\''; static final char DQ = '"'; static final char DOLLAR = '$'; @@ -57,7 +58,7 @@ static final String DIV = "div"; static final String MOD = "mod"; static final String QUO = "quo"; - static final String DOT = "."; + static final String DOT_STR = "."; static final String DDOT = ".."; static final String DCOLON = "::"; static final String ATTR = "attribute"; diff -Nru openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/XPathParser.java openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/XPathParser.java --- openjdk-17-17.0.3+7/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/XPathParser.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/XPathParser.java 2022-07-14 08:05:38.000000000 +0000 @@ -35,7 +35,7 @@ * Tokenizes and parses XPath expressions. This should really be named * XPathParserImpl, and may be renamed in the future. * @xsl.usage general - * @LastModified: Jan 2022 + * @LastModified: Apr 2022 */ public class XPathParser { @@ -1413,7 +1413,7 @@ matchFound = true; } - else if (lookahead(Token.LPAREN, 1) || (lookahead(Token.COLON_CHAR, 1) && lookahead(Token.LPAREN, 3))) + else if (lookahead(Token.LPAREN, 1) || (lookahead(Token.COLON, 1) && lookahead(Token.LPAREN, 3))) { matchFound = FunctionCall(); } @@ -1457,7 +1457,7 @@ int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); - if (lookahead(Token.COLON_CHAR, 1)) + if (lookahead(Token.COLON, 1)) { appendOp(4, OpCodes.OP_EXTFUNCTION); @@ -1661,7 +1661,7 @@ opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); } - if (tokenIs(Token.DOT)) + if (tokenIs(Token.DOT_STR)) { nextToken(); @@ -1841,7 +1841,7 @@ m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), OpCodes.NODENAME); m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) + 1); - if (lookahead(Token.COLON_CHAR, 1)) + if (lookahead(Token.COLON, 1)) { if (tokenIs(Token.STAR)) { @@ -1944,7 +1944,7 @@ protected void QName() throws TransformerException { // Namespace - if(lookahead(Token.COLON_CHAR, 1)) + if(lookahead(Token.COLON, 1)) { m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), m_queueMark - 1); m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) + 1); diff -Nru openjdk-17-17.0.3+7/src/java.xml/share/legal/bcel.md openjdk-17-17.0.4+8/src/java.xml/share/legal/bcel.md --- openjdk-17-17.0.3+7/src/java.xml/share/legal/bcel.md 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml/share/legal/bcel.md 2022-07-14 08:05:38.000000000 +0000 @@ -3,14 +3,11 @@ ### Apache Commons BCEL Notice
     
    -    =========================================================================
    -    ==  NOTICE file corresponding to the section 4 d of                    ==
    -    ==  the Apache License, Version 2.0,                                   ==
    -    ==  in this case for the Apache Commons BCEL distribution.             ==
    -    =========================================================================
    +    Apache Commons BCEL
    +    Copyright 2004-2020 The Apache Software Foundation
     
    -   This product includes software developed by
    -   The Apache Software Foundation (http://www.apache.org/).
    +    This product includes software developed at
    +    The Apache Software Foundation (https://www.apache.org/).
     
     
    diff -Nru openjdk-17-17.0.3+7/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java openjdk-17-17.0.4+8/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java --- openjdk-17-17.0.3+7/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java 2022-07-14 08:05:38.000000000 +0000 @@ -21,7 +21,7 @@ * under the License. */ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. */ package org.jcp.xml.dsig.internal.dom; @@ -101,7 +101,9 @@ if (id.startsWith("xpointer(id(")) { int i1 = id.indexOf('\''); int i2 = id.indexOf('\'', i1+1); - id = id.substring(i1+1, i2); + if (i1 >= 0 && i2 >= 0) { + id = id.substring(i1 + 1, i2); + } } // check if element is registered by Id diff -Nru openjdk-17-17.0.3+7/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Utils.java openjdk-17-17.0.4+8/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Utils.java --- openjdk-17-17.0.3+7/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Utils.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Utils.java 2022-07-14 08:05:38.000000000 +0000 @@ -21,7 +21,7 @@ * under the License. */ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. */ package org.jcp.xml.dsig.internal.dom; @@ -94,7 +94,9 @@ if (id.startsWith("xpointer(id(")) { int i1 = id.indexOf('\''); int i2 = id.indexOf('\'', i1+1); - id = id.substring(i1+1, i2); + if (i1 >= 0 && i2 >= 0) { + id = id.substring(i1 + 1, i2); + } } return id; } diff -Nru openjdk-17-17.0.3+7/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java openjdk-17-17.0.4+8/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java --- openjdk-17-17.0.3+7/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java 2022-07-14 08:05:38.000000000 +0000 @@ -27,6 +27,7 @@ import java.awt.*; import java.awt.event.*; +import java.awt.geom.AffineTransform; import java.util.*; import java.lang.*; import java.lang.reflect.*; @@ -478,6 +479,9 @@ if (parent == null) { return null; } + Point userSpaceXY = AccessibilityGraphicsEnvironment.toUserSpace(x, y); + x = userSpaceXY.x; + y = userSpaceXY.y; if (windowHandleToContextMap != null && windowHandleToContextMap.containsValue(getRootAccessibleContext(parent))) { // Path for applications that register their top-level @@ -1593,6 +1597,8 @@ if (p != null) { r.x = p.x; r.y = p.y; + + r = AccessibilityGraphicsEnvironment.toDeviceSpaceAbs(r); return r; } } catch (Exception e) { @@ -2257,6 +2263,7 @@ if (s != null && s.equals("\n")) { rect.width = 0; } + rect = AccessibilityGraphicsEnvironment.toDeviceSpaceAbs(rect); return rect; } } @@ -7338,4 +7345,182 @@ } } } + + /** + * A helper class to handle coordinate conversion between screen and user spaces. + * See {@link sun.java2d.SunGraphicsEnvironment} + */ + private static abstract class AccessibilityGraphicsEnvironment extends GraphicsEnvironment { + /** + * Returns the graphics configuration which bounds contain the given point in the user's space. + * + * See {@link sun.java2d.SunGraphicsEnvironment#getGraphicsConfigurationAtPoint(GraphicsConfiguration, double, double)} + * + * @param x the x coordinate of the given point in the user's space + * @param y the y coordinate of the given point in the user's space + * @return the graphics configuration + */ + public static GraphicsConfiguration getGraphicsConfigurationAtPoint(double x, double y) { + GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + return getGraphicsConfigurationAtPoint(gc, x, y); + } + + /** + * Returns the graphics configuration which bounds contain the given point in the user's space. + * + * See {@link sun.java2d.SunGraphicsEnvironment#getGraphicsConfigurationAtPoint(GraphicsConfiguration, double, double)} + * + * @param current the default configuration which is checked in the first + * place + * @param x the x coordinate of the given point in the user's space + * @param y the y coordinate of the given point in the user's space + * @return the graphics configuration + */ + public static GraphicsConfiguration getGraphicsConfigurationAtPoint( + GraphicsConfiguration current, double x, double y) { + if (containsUserSpacePoint(current, x, y)) { + return current; + } + GraphicsEnvironment env = getLocalGraphicsEnvironment(); + for (GraphicsDevice device : env.getScreenDevices()) { + GraphicsConfiguration config = device.getDefaultConfiguration(); + if (containsUserSpacePoint(config, x, y)) { + return config; + } + } + return current; + } + + /** + * Returns the graphics configuration which bounds contain the given point in the device space. + * + * @param x the x coordinate of the given point in the device space + * @param y the y coordinate of the given point in the device space + * @return the graphics configuration + */ + public static GraphicsConfiguration getGraphicsConfigurationAtDevicePoint(double x, double y) { + GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + return getGraphicsConfigurationAtDevicePoint(gc, x, y); + } + + /** + * Returns the graphics configuration which bounds contain the given point in the device space. + * + * @param current the default configuration which is checked in the first + * place + * @param x the x coordinate of the given point in the device space + * @param y the y coordinate of the given point in the device space + * @return the graphics configuration + */ + public static GraphicsConfiguration getGraphicsConfigurationAtDevicePoint( + GraphicsConfiguration current, double x, double y) { + if (containsDeviceSpacePoint(current, x, y)) { + return current; + } + GraphicsEnvironment env = getLocalGraphicsEnvironment(); + for (GraphicsDevice device : env.getScreenDevices()) { + GraphicsConfiguration config = device.getDefaultConfiguration(); + if (containsDeviceSpacePoint(config, x, y)) { + return config; + } + } + return current; + } + + private static boolean containsDeviceSpacePoint(GraphicsConfiguration config, double x, double y) { + Rectangle bounds = config.getBounds(); + bounds = toDeviceSpaceAbs(config, bounds.x, bounds.y, bounds.width, bounds.height); + return bounds.contains(x, y); + } + + private static boolean containsUserSpacePoint(GraphicsConfiguration config, double x, double y) { + Rectangle bounds = config.getBounds(); + return bounds.contains(x, y); + } + + /** + * Converts absolute coordinates from the device + * space to the user's space space using appropriate device transformation. + * + * @param x absolute x coordinate in the device's space + * @param y absolute y coordinate in the device's space + * @return the corresponding coordinates in user's space + */ + public static Point toUserSpace(int x, int y) { + GraphicsConfiguration gc = getGraphicsConfigurationAtDevicePoint(x, y); + return toUserSpace(gc, x, y); + } + + /** + * Converts absolute coordinates from the device + * space to the user's space using passed graphics configuration. + * + * @param gc the graphics configuration to be used for transformation + * @param x absolute x coordinate in the device's space + * @param y absolute y coordinate in the device's space + * @return the corresponding coordinates in user's space + */ + public static Point toUserSpace(GraphicsConfiguration gc, int x, int y) { + AffineTransform tx = gc.getDefaultTransform(); + Rectangle screen = gc.getBounds(); + int userX = screen.x + clipRound((x - screen.x) / tx.getScaleX()); + int userY = screen.y + clipRound((y - screen.y) / tx.getScaleY()); + return new Point(userX, userY); + } + + /** + * Converts the rectangle from the user's space to the device space using + * appropriate device transformation. + * + * See {@link sun.java2d.SunGraphicsEnvironment#toDeviceSpaceAbs(Rectangle)} + * + * @param rect the rectangle in the user's space + * @return the rectangle which uses device space (pixels) + */ + public static Rectangle toDeviceSpaceAbs(Rectangle rect) { + GraphicsConfiguration gc = getGraphicsConfigurationAtPoint(rect.x, rect.y); + return toDeviceSpaceAbs(gc, rect.x, rect.y, rect.width, rect.height); + } + + /** + * Converts absolute coordinates (x, y) and the size (w, h) from the user's + * space to the device space using passed graphics configuration. + * + * See {@link sun.java2d.SunGraphicsEnvironment#toDeviceSpaceAbs(GraphicsConfiguration, int, int, int, int)} + * + * @param gc the graphics configuration to be used for transformation + * @param x absolute coordinate in the user's space + * @param y absolute coordinate in the user's space + * @param w the width in the user's space + * @param h the height in the user's space + * @return the rectangle which uses device space (pixels) + */ + public static Rectangle toDeviceSpaceAbs(GraphicsConfiguration gc, + int x, int y, int w, int h) { + AffineTransform tx = gc.getDefaultTransform(); + Rectangle screen = gc.getBounds(); + return new Rectangle( + screen.x + clipRound((x - screen.x) * tx.getScaleX()), + screen.y + clipRound((y - screen.y) * tx.getScaleY()), + clipRound(w * tx.getScaleX()), + clipRound(h * tx.getScaleY()) + ); + } + + /** + * See {@link sun.java2d.pipe.Region#clipRound} + */ + private static int clipRound(final double coordinate) { + final double newv = coordinate - 0.5; + if (newv < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + if (newv > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + return (int) Math.ceil(newv); + } + } } diff -Nru openjdk-17-17.0.3+7/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java openjdk-17-17.0.4+8/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java --- openjdk-17-17.0.3+7/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import java.util.zip.ZipException; import javax.lang.model.SourceVersion; import javax.tools.FileObject; @@ -564,7 +565,11 @@ Map env = Collections.singletonMap("multi-release", multiReleaseValue); FileSystemProvider jarFSProvider = fsInfo.getJarFSProvider(); Assert.checkNonNull(jarFSProvider, "should have been caught before!"); - this.fileSystem = jarFSProvider.newFileSystem(archivePath, env); + try { + this.fileSystem = jarFSProvider.newFileSystem(archivePath, env); + } catch (ZipException ze) { + throw new IOException("ZipException opening \"" + archivePath.getFileName() + "\": " + ze.getMessage(), ze); + } } else { this.fileSystem = FileSystems.newFileSystem(archivePath, (ClassLoader)null); } diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/globals_vectorApiSupport_linux.S.inc openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/globals_vectorApiSupport_linux.S.inc --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/globals_vectorApiSupport_linux.S.inc 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/globals_vectorApiSupport_linux.S.inc 2022-07-14 08:05:38.000000000 +0000 @@ -1,10 +1,12 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * 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. + * 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 diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_acos_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_acos_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_acos_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_acos_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_acos.c" .text ..TXTST0: .L_2__routine_start___jsvml_acos2_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_asin_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_asin_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_asin_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_asin_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_asin.c" .text ..TXTST0: .L_2__routine_start___jsvml_asin2_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_atan2_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_atan2_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_atan2_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_atan2_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_atan2.c" .text ..TXTST0: .L_2__routine_start___jsvml_atan22_ha_ex_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_atan_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_atan_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_atan_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_atan_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_atan.c" .text ..TXTST0: .L_2__routine_start___jsvml_atan2_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cbrt_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cbrt_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cbrt_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cbrt_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_cbrt.c" .text ..TXTST0: .L_2__routine_start___jsvml_cbrt1_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cosh_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cosh_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cosh_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cosh_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_cosh.c" .text ..TXTST0: .L_2__routine_start___jsvml_cosh1_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cos_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cos_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cos_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_cos_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_cos.c" .text ..TXTST0: .L_2__routine_start___jsvml_cos2_ha_ex_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_exp_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_exp_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_exp_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_exp_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_exp.c" .text ..TXTST0: .L_2__routine_start___jsvml_exp1_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_expm1_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_expm1_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_expm1_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_expm1_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_expm1.c" .text ..TXTST0: .L_2__routine_start___jsvml_expm14_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_hypot_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_hypot_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_hypot_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_hypot_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_hypot.c" .text ..TXTST0: .L_2__routine_start___jsvml_hypot2_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log10_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log10_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log10_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log10_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_log10.c" .text ..TXTST0: .L_2__routine_start___jsvml_log102_ha_ex_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log1p_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log1p_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log1p_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log1p_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_log1p.c" .text ..TXTST0: .L_2__routine_start___jsvml_log1p4_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_log_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_log.c" .text ..TXTST0: .L_2__routine_start___jsvml_log1_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_pow_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_pow_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_pow_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_pow_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_pow.c" .text ..TXTST0: .L_2__routine_start___jsvml_pow2_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_sinh_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_sinh_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_sinh_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_sinh_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_sinh.c" .text ..TXTST0: .L_2__routine_start___jsvml_sinh1_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_sin_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_sin_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_sin_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_sin_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_sin.c" .text ..TXTST0: .L_2__routine_start___jsvml_sin2_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_tanh_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_tanh_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_tanh_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_tanh_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_tanh.c" .text ..TXTST0: .L_2__routine_start___jsvml_tanh4_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_tan_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_tan_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_tan_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_d_tan_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_d_tan.c" .text ..TXTST0: .L_2__routine_start___jsvml_tan1_ha_ex_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_acos_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_acos_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_acos_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_acos_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_acos.c" .text ..TXTST0: .L_2__routine_start___jsvml_acosf16_ha_z0_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_asin_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_asin_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_asin_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_asin_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_asin.c" .text ..TXTST0: .L_2__routine_start___jsvml_asinf8_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_atan2_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_atan2_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_atan2_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_atan2_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_atan2.c" .text ..TXTST0: .L_2__routine_start___jsvml_atan2f4_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_atan_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_atan_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_atan_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_atan_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_atan.c" .text ..TXTST0: .L_2__routine_start___jsvml_atanf8_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cbrt_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cbrt_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cbrt_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cbrt_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_cbrt.c" .text ..TXTST0: .L_2__routine_start___jsvml_cbrtf4_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cosh_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cosh_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cosh_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cosh_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_cosh.c" .text ..TXTST0: .L_2__routine_start___jsvml_coshf16_ha_z0_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cos_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cos_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cos_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_cos_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_cos.c" .text ..TXTST0: .L_2__routine_start___jsvml_cosf8_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_exp_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_exp_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_exp_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_exp_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_exp.c" .text ..TXTST0: .L_2__routine_start___jsvml_expf4_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_expm1_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_expm1_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_expm1_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_expm1_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_expm1.c" .text ..TXTST0: .L_2__routine_start___jsvml_expm1f4_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_hypot_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_hypot_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_hypot_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_hypot_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_hypot.c" .text ..TXTST0: .L_2__routine_start___jsvml_hypotf8_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log10_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log10_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log10_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log10_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_log10.c" .text ..TXTST0: .L_2__routine_start___jsvml_log10f4_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log1p_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log1p_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log1p_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log1p_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_log1p.c" .text ..TXTST0: .L_2__routine_start___jsvml_log1pf4_ha_e9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_log_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_log.c" .text ..TXTST0: .L_2__routine_start___jsvml_logf4_ha_ex_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_pow_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_pow_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_pow_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_pow_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_pow.c" .text ..TXTST0: .L_2__routine_start___jsvml_powf16_ha_z0_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_sinh_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_sinh_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_sinh_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_sinh_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_sinh.c" .text ..TXTST0: .L_2__routine_start___jsvml_sinhf4_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_sin_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_sin_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_sin_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_sin_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_sin.c" .text ..TXTST0: .L_2__routine_start___jsvml_sinf16_ha_z0_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_tanh_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_tanh_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_tanh_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_tanh_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_tanh.c" .text ..TXTST0: .L_2__routine_start___jsvml_tanhf4_ha_l9_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_tan_linux_x86.S openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_tan_linux_x86.S --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_tan_linux_x86.S 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/linux/native/libjsvml/jsvml_s_tan_linux_x86.S 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Intel Corporation. All rights reserved. + * Copyright (c) 2018, 2022, Intel Corporation. All rights reserved. * Intel Short Vector Math Library (SVML) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,7 +28,6 @@ #include "globals_vectorApiSupport_linux.S.inc" #ifdef __VECTOR_API_MATH_INTRINSICS_LINUX # -- Machine type EM64t - .file "svml_s_tan.c" .text ..TXTST0: .L_2__routine_start___jsvml_tanf4_ha_ex_0: diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java 2022-07-14 08:05:38.000000000 +0000 @@ -4029,12 +4029,12 @@ */ static ByteSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (ByteSpecies) SPECIES_64; - case S_128_BIT: return (ByteSpecies) SPECIES_128; - case S_256_BIT: return (ByteSpecies) SPECIES_256; - case S_512_BIT: return (ByteSpecies) SPECIES_512; - case S_Max_BIT: return (ByteSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (ByteSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (ByteSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (ByteSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (ByteSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (ByteSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java 2022-07-14 08:05:38.000000000 +0000 @@ -3631,12 +3631,12 @@ */ static DoubleSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (DoubleSpecies) SPECIES_64; - case S_128_BIT: return (DoubleSpecies) SPECIES_128; - case S_256_BIT: return (DoubleSpecies) SPECIES_256; - case S_512_BIT: return (DoubleSpecies) SPECIES_512; - case S_Max_BIT: return (DoubleSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (DoubleSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (DoubleSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (DoubleSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (DoubleSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (DoubleSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java 2022-07-14 08:05:38.000000000 +0000 @@ -3618,12 +3618,12 @@ */ static FloatSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (FloatSpecies) SPECIES_64; - case S_128_BIT: return (FloatSpecies) SPECIES_128; - case S_256_BIT: return (FloatSpecies) SPECIES_256; - case S_512_BIT: return (FloatSpecies) SPECIES_512; - case S_Max_BIT: return (FloatSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (FloatSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (FloatSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (FloatSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (FloatSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (FloatSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java 2022-07-14 08:05:38.000000000 +0000 @@ -3727,12 +3727,12 @@ */ static IntSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (IntSpecies) SPECIES_64; - case S_128_BIT: return (IntSpecies) SPECIES_128; - case S_256_BIT: return (IntSpecies) SPECIES_256; - case S_512_BIT: return (IntSpecies) SPECIES_512; - case S_Max_BIT: return (IntSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (IntSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (IntSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (IntSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (IntSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (IntSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java 2022-07-14 08:05:38.000000000 +0000 @@ -3621,12 +3621,12 @@ */ static LongSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (LongSpecies) SPECIES_64; - case S_128_BIT: return (LongSpecies) SPECIES_128; - case S_256_BIT: return (LongSpecies) SPECIES_256; - case S_512_BIT: return (LongSpecies) SPECIES_512; - case S_Max_BIT: return (LongSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (LongSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (LongSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (LongSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (LongSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (LongSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java 2022-07-14 08:05:38.000000000 +0000 @@ -4024,12 +4024,12 @@ */ static ShortSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (ShortSpecies) SPECIES_64; - case S_128_BIT: return (ShortSpecies) SPECIES_128; - case S_256_BIT: return (ShortSpecies) SPECIES_256; - case S_512_BIT: return (ShortSpecies) SPECIES_512; - case S_Max_BIT: return (ShortSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (ShortSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (ShortSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (ShortSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (ShortSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (ShortSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,6 +68,8 @@ * *
  • {@code ESIZE} — the size in bytes of the operand type * + *
  • {@code EMASK} — the bit mask of the operand type, where {@code EMASK=(1<<(ESIZE*8))-1} + * *
  • {@code intVal}, {@code byteVal}, etc. — the operand of a * conversion, with the indicated type * @@ -548,7 +550,7 @@ public static final /*bitwise*/ Binary LSHL = binary("LSHL", "<<", VectorSupport.VECTOR_OP_LSHIFT, VO_SHIFT); /** Produce {@code a>>(n&(ESIZE*8-1))}. Integral only. */ public static final /*bitwise*/ Binary ASHR = binary("ASHR", ">>", VectorSupport.VECTOR_OP_RSHIFT, VO_SHIFT); - /** Produce {@code a>>>(n&(ESIZE*8-1))}. Integral only. */ + /** Produce {@code (a&EMASK)>>>(n&(ESIZE*8-1))}. Integral only. */ public static final /*bitwise*/ Binary LSHR = binary("LSHR", ">>>", VectorSupport.VECTOR_OP_URSHIFT, VO_SHIFT); /** Produce {@code rotateLeft(a,n)}. Integral only. */ public static final /*bitwise*/ Binary ROL = binary("ROL", "rotateLeft", -1 /*VectorSupport.VECTOR_OP_LROTATE*/, VO_SHIFT | VO_SPECIAL); diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template 2022-07-14 08:05:38.000000000 +0000 @@ -5033,12 +5033,12 @@ */ static $Type$Species species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return ($Type$Species) SPECIES_64; - case S_128_BIT: return ($Type$Species) SPECIES_128; - case S_256_BIT: return ($Type$Species) SPECIES_256; - case S_512_BIT: return ($Type$Species) SPECIES_512; - case S_Max_BIT: return ($Type$Species) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return ($Type$Species) SPECIES_64; + case VectorShape.SK_128_BIT: return ($Type$Species) SPECIES_128; + case VectorShape.SK_256_BIT: return ($Type$Species) SPECIES_256; + case VectorShape.SK_512_BIT: return ($Type$Species) SPECIES_512; + case VectorShape.SK_Max_BIT: return ($Type$Species) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff -Nru openjdk-17-17.0.3+7/src/jdk.incubator.vector/windows/native/libjsvml/globals_vectorApiSupport_windows.S.inc openjdk-17-17.0.4+8/src/jdk.incubator.vector/windows/native/libjsvml/globals_vectorApiSupport_windows.S.inc --- openjdk-17-17.0.3+7/src/jdk.incubator.vector/windows/native/libjsvml/globals_vectorApiSupport_windows.S.inc 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.incubator.vector/windows/native/libjsvml/globals_vectorApiSupport_windows.S.inc 2022-07-14 08:05:38.000000000 +0000 @@ -1,9 +1,11 @@ -; Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. +; Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. ; 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. +; 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 diff -Nru openjdk-17-17.0.3+7/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java openjdk-17-17.0.4+8/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java --- openjdk-17-17.0.3+7/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -849,7 +849,7 @@ /** * @see HotSpotJVMCIRuntime#translate(Object) */ - native long translate(Object obj); + native long translate(Object obj, boolean callPostTranslation); /** * @see HotSpotJVMCIRuntime#unhand(Class, long) diff -Nru openjdk-17-17.0.3+7/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java openjdk-17-17.0.4+8/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java --- openjdk-17-17.0.3+7/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * 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,6 +46,8 @@ import java.util.Objects; import java.util.ServiceLoader; import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.Architecture; @@ -66,6 +68,7 @@ import jdk.vm.ci.runtime.JVMCICompilerFactory; import jdk.vm.ci.runtime.JVMCIRuntime; import jdk.vm.ci.services.JVMCIServiceLocator; +import jdk.vm.ci.services.Services; /** * HotSpot implementation of a JVMCI runtime. @@ -199,14 +202,44 @@ return result; } + /** + * Decodes the exception encoded in {@code buffer} and throws it. + * + * @param buffer a native byte buffer containing an exception encoded by + * {@link #encodeThrowable} + */ @VMEntryPoint - static Throwable decodeThrowable(String encodedThrowable) throws Throwable { - return TranslatedException.decodeThrowable(encodedThrowable); + static void decodeAndThrowThrowable(long buffer) throws Throwable { + Unsafe unsafe = UnsafeAccess.UNSAFE; + int encodingLength = unsafe.getInt(buffer); + byte[] encoding = new byte[encodingLength]; + unsafe.copyMemory(null, buffer + 4, encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, encodingLength); + throw TranslatedException.decodeThrowable(encoding); } + /** + * If {@code bufferSize} is large enough, encodes {@code throwable} into a byte array and writes + * it to {@code buffer}. The encoding in {@code buffer} can be decoded by + * {@link #decodeAndThrowThrowable}. + * + * @param throwable the exception to encode + * @param buffer a native byte buffer + * @param bufferSize the size of {@code buffer} in bytes + * @return the number of bytes written into {@code buffer} if {@code bufferSize} is large + * enough, otherwise {@code -N} where {@code N} is the value {@code bufferSize} needs to + * be to fit the encoding + */ @VMEntryPoint - static String encodeThrowable(Throwable throwable) throws Throwable { - return TranslatedException.encodeThrowable(throwable); + static int encodeThrowable(Throwable throwable, long buffer, int bufferSize) throws Throwable { + byte[] encoding = TranslatedException.encodeThrowable(throwable); + int requiredSize = 4 + encoding.length; + if (bufferSize < requiredSize) { + return -requiredSize; + } + Unsafe unsafe = UnsafeAccess.UNSAFE; + unsafe.putInt(buffer, encoding.length); + unsafe.copyMemory(encoding, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, buffer + 4, encoding.length); + return requiredSize; } @VMEntryPoint @@ -235,6 +268,10 @@ // Note: The following one is not used (see InitTimer.ENABLED). It is added here // so that -XX:+JVMCIPrintProperties shows the option. InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."), + ForceTranslateFailure(String.class, null, "Forces HotSpotJVMCIRuntime.translate to throw an exception in the context " + + "of the peer runtime. The value is a filter that can restrict the forced failure to matching translated " + + "objects. See HotSpotJVMCIRuntime.postTranslation for more details. This option exists soley to test " + + "correct handling of translation failure."), PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."), AuditHandles(Boolean.class, false, "Record stack trace along with scoped foreign object reference wrappers " + "to debug issue with a wrapper being used after its scope has closed."), @@ -1140,7 +1177,88 @@ * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" */ public long translate(Object obj) { - return compilerToVm.translate(obj); + return compilerToVm.translate(obj, Option.ForceTranslateFailure.getString() != null); + } + + private static final Pattern FORCE_TRANSLATE_FAILURE_FILTER_RE = Pattern.compile("(?:(method|type|nmethod)/)?([^:]+)(?::(hotspot|native))?"); + + /** + * Forces translation failure based on {@code translatedObject} and the value of + * {@link Option#ForceTranslateFailure}. The value is zero or more filters separated by a comma. + * The syntax for a filter is: + * + *
    +     *   Filter = [ TypeSelector "/" ] Substring [ ":" JVMCIEnvSelector ] .
    +     *   TypeSelector = "type" | "method" | "nmethod"
    +     *   JVMCIEnvSelector = "native" | "hotspot"
    +     * 
    + * + * For example: + * + *
    +     *   -Djvmci.ForceTranslateFailure=nmethod/StackOverflowError:native,method/computeHash,execute
    +     * 
    + * + * will cause failure of: + *
      + *
    • translating a {@link HotSpotNmethod} to the libjvmci heap whose fully qualified name + * contains "StackOverflowError"
    • + *
    • translating a {@link HotSpotResolvedJavaMethodImpl} to the libjvmci or HotSpot heap whose + * fully qualified name contains "computeHash"
    • + *
    • translating a {@link HotSpotNmethod}, {@link HotSpotResolvedJavaMethodImpl} or + * {@link HotSpotResolvedObjectTypeImpl} to the libjvmci or HotSpot heap whose fully qualified + * name contains "execute"
    • + *
    + */ + @VMEntryPoint + static void postTranslation(Object translatedObject) { + String value = Option.ForceTranslateFailure.getString(); + String toMatch; + String type; + if (translatedObject instanceof HotSpotResolvedJavaMethodImpl) { + toMatch = ((HotSpotResolvedJavaMethodImpl) translatedObject).format("%H.%n"); + type = "method"; + } else if (translatedObject instanceof HotSpotResolvedObjectTypeImpl) { + toMatch = ((HotSpotResolvedObjectTypeImpl) translatedObject).toJavaName(); + type = "type"; + } else if (translatedObject instanceof HotSpotNmethod) { + HotSpotNmethod nmethod = (HotSpotNmethod) translatedObject; + if (nmethod.getMethod() != null) { + toMatch = nmethod.getMethod().format("%H.%n"); + } else { + toMatch = String.valueOf(nmethod.getName()); + } + type = "nmethod"; + } else { + return; + } + String[] filters = value.split(","); + for (String filter : filters) { + Matcher m = FORCE_TRANSLATE_FAILURE_FILTER_RE.matcher(filter); + if (!m.matches()) { + throw new JVMCIError(Option.ForceTranslateFailure + " filter does not match " + FORCE_TRANSLATE_FAILURE_FILTER_RE + ": " + filter); + } + String typeSelector = m.group(1); + String substring = m.group(2); + String jvmciEnvSelector = m.group(3); + if (jvmciEnvSelector != null) { + if (jvmciEnvSelector.equals("native")) { + if (!Services.IS_IN_NATIVE_IMAGE) { + continue; + } + } else { + if (Services.IS_IN_NATIVE_IMAGE) { + continue; + } + } + } + if (typeSelector != null && !typeSelector.equals(type)) { + continue; + } + if (toMatch.contains(substring)) { + throw new JVMCIError("translation of " + translatedObject + " failed due to matching " + Option.ForceTranslateFailure + " filter \"" + filter + "\""); + } + } } /** diff -Nru openjdk-17-17.0.3+7/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java openjdk-17-17.0.4+8/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java --- openjdk-17-17.0.3+7/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * 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,13 +22,20 @@ */ package jdk.vm.ci.hotspot; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Formatter; import java.util.List; -import java.util.Objects; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import jdk.vm.ci.common.JVMCIError; /** * Support for translating exceptions between different runtime heaps. @@ -37,6 +44,26 @@ final class TranslatedException extends Exception { /** + * The value returned by {@link #encodeThrowable(Throwable)} when encoding fails due to an + * {@link OutOfMemoryError}. + */ + private static final byte[] FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES; + + /** + * The value returned by {@link #encodeThrowable(Throwable)} when encoding fails for any reason + * other than {@link OutOfMemoryError}. + */ + private static final byte[] FALLBACK_ENCODED_THROWABLE_BYTES; + static { + try { + FALLBACK_ENCODED_THROWABLE_BYTES = encodeThrowable(new TranslatedException("error during encoding", ""), false); + FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES = encodeThrowable(new OutOfMemoryError(), false); + } catch (IOException e) { + throw new JVMCIError(e); + } + } + + /** * Class name of exception that could not be instantiated. */ private String originalExceptionClassName; @@ -110,83 +137,74 @@ } } - /** - * Encodes an exception message to distinguish a null message from an empty message. - * - * @return {@code value} with a space prepended iff {@code value != null} - */ - private static String encodeMessage(String value) { - return value != null ? ' ' + value : value; - } - - private static String decodeMessage(String value) { - if (value.length() == 0) { - return null; - } - return value.substring(1); + private static String emptyIfNull(String value) { + return value == null ? "" : value; } - private static String encodedString(String value) { - return Objects.toString(value, "").replace('|', '_'); + private static String emptyAsNull(String value) { + return value.isEmpty() ? null : value; } /** - * Encodes {@code throwable} including its stack and causes as a string. The encoding format of - * a single exception is: - * - *
    -     *  '|'  '|'  '|' [  '|'  '|'  '|'  '|'  '|'  '|'  '|' ]*
    -     * 
    - * - * Each exception is encoded before the exception it causes. + * Encodes {@code throwable} including its stack and causes as a {@linkplain GZIPOutputStream + * compressed} byte array that can be decoded by {@link #decodeThrowable}. */ @VMEntryPoint - static String encodeThrowable(Throwable throwable) throws Throwable { + static byte[] encodeThrowable(Throwable throwable) throws Throwable { try { - Formatter enc = new Formatter(); + return encodeThrowable(throwable, true); + } catch (OutOfMemoryError e) { + return FALLBACK_ENCODED_OUTOFMEMORYERROR_BYTES; + } catch (Throwable e) { + return FALLBACK_ENCODED_THROWABLE_BYTES; + } + } + + private static byte[] encodeThrowable(Throwable throwable, boolean withCauseAndStack) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(baos))) { List throwables = new ArrayList<>(); for (Throwable current = throwable; current != null; current = current.getCause()) { throwables.add(current); + if (!withCauseAndStack) { + break; + } } // Encode from inner most cause outwards Collections.reverse(throwables); for (Throwable current : throwables) { - enc.format("%s|%s|", current.getClass().getName(), encodedString(encodeMessage(current.getMessage()))); - StackTraceElement[] stackTrace = current.getStackTrace(); + dos.writeUTF(current.getClass().getName()); + dos.writeUTF(emptyIfNull(current.getMessage())); + StackTraceElement[] stackTrace = withCauseAndStack ? current.getStackTrace() : null; if (stackTrace == null) { stackTrace = new StackTraceElement[0]; } - enc.format("%d|", stackTrace.length); + dos.writeInt(stackTrace.length); for (int i = 0; i < stackTrace.length; i++) { StackTraceElement frame = stackTrace[i]; if (frame != null) { - enc.format("%s|%s|%s|%s|%s|%s|%d|", encodedString(frame.getClassLoaderName()), - encodedString(frame.getModuleName()), encodedString(frame.getModuleVersion()), - frame.getClassName(), frame.getMethodName(), - encodedString(frame.getFileName()), frame.getLineNumber()); + dos.writeUTF(emptyIfNull(frame.getClassLoaderName())); + dos.writeUTF(emptyIfNull(frame.getModuleName())); + dos.writeUTF(emptyIfNull(frame.getModuleVersion())); + dos.writeUTF(emptyIfNull(frame.getClassName())); + dos.writeUTF(emptyIfNull(frame.getMethodName())); + dos.writeUTF(emptyIfNull(frame.getFileName())); + dos.writeInt(frame.getLineNumber()); } } } - return enc.toString(); - } catch (Throwable e) { - assert printStackTrace(e); - try { - return e.getClass().getName() + "|" + encodedString(e.getMessage()) + "|0|"; - } catch (Throwable e2) { - assert printStackTrace(e2); - return "java.lang.Throwable|too many errors during encoding|0|"; - } } + return baos.toByteArray(); } /** * Gets the stack of the current thread without the frames between this call and the one just - * below the frame of the first method in {@link CompilerToVM}. The chopped frames are specific - * to the implementation of {@link HotSpotJVMCIRuntime#decodeThrowable(String)}. + * below the frame of the first method in {@link CompilerToVM}. The chopped frames are for the + * VM call to {@link HotSpotJVMCIRuntime#decodeAndThrowThrowable}. */ - private static StackTraceElement[] getStackTraceSuffix() { + private static StackTraceElement[] getMyStackTrace() { StackTraceElement[] stack = new Exception().getStackTrace(); for (int i = 0; i < stack.length; i++) { StackTraceElement e = stack[i]; @@ -206,43 +224,47 @@ * {@link #encodeThrowable} */ @VMEntryPoint - static Throwable decodeThrowable(String encodedThrowable) { - try { - int i = 0; - String[] parts = encodedThrowable.split("\\|"); + static Throwable decodeThrowable(byte[] encodedThrowable) { + try (DataInputStream dis = new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(encodedThrowable)))) { Throwable cause = null; Throwable throwable = null; - while (i != parts.length) { - String exceptionClassName = parts[i++]; - String exceptionMessage = decodeMessage(parts[i++]); + StackTraceElement[] myStack = getMyStackTrace(); + while (dis.available() != 0) { + String exceptionClassName = dis.readUTF(); + String exceptionMessage = emptyAsNull(dis.readUTF()); throwable = create(exceptionClassName, exceptionMessage, cause); - int stackTraceDepth = Integer.parseInt(parts[i++]); - - StackTraceElement[] suffix = getStackTraceSuffix(); - StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + suffix.length]; + int stackTraceDepth = dis.readInt(); + StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + myStack.length]; + int stackTraceIndex = 0; + int myStackIndex = 0; for (int j = 0; j < stackTraceDepth; j++) { - String classLoaderName = parts[i++]; - String moduleName = parts[i++]; - String moduleVersion = parts[i++]; - String className = parts[i++]; - String methodName = parts[i++]; - String fileName = parts[i++]; - int lineNumber = Integer.parseInt(parts[i++]); - if (classLoaderName.isEmpty()) { - classLoaderName = null; + String classLoaderName = emptyAsNull(dis.readUTF()); + String moduleName = emptyAsNull(dis.readUTF()); + String moduleVersion = emptyAsNull(dis.readUTF()); + String className = emptyAsNull(dis.readUTF()); + String methodName = emptyAsNull(dis.readUTF()); + String fileName = emptyAsNull(dis.readUTF()); + int lineNumber = dis.readInt(); + StackTraceElement ste = new StackTraceElement(classLoaderName, moduleName, moduleVersion, className, methodName, fileName, lineNumber); + + if (ste.isNativeMethod()) { + // Best effort attempt to weave stack traces from two heaps into + // a single stack trace using native method frames as stitching points. + // This is not 100% reliable as there's no guarantee that native method + // frames only exist for calls between HotSpot and libjvmci. + while (myStackIndex < myStack.length) { + StackTraceElement suffixSTE = myStack[myStackIndex++]; + if (suffixSTE.isNativeMethod()) { + break; + } + stackTrace[stackTraceIndex++] = suffixSTE; + } } - if (moduleName.isEmpty()) { - moduleName = null; - } - if (moduleVersion.isEmpty()) { - moduleVersion = null; - } - if (fileName.isEmpty()) { - fileName = null; - } - stackTrace[j] = new StackTraceElement(classLoaderName, moduleName, moduleVersion, className, methodName, fileName, lineNumber); + stackTrace[stackTraceIndex++] = ste; + } + while (myStackIndex < myStack.length) { + stackTrace[stackTraceIndex++] = myStack[myStackIndex++]; } - System.arraycopy(suffix, 0, stackTrace, stackTraceDepth, suffix.length); throwable.setStackTrace(stackTrace); cause = throwable; } diff -Nru openjdk-17-17.0.3+7/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java openjdk-17-17.0.4+8/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java --- openjdk-17-17.0.3+7/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * 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,11 @@ */ public class MetaUtil { + public static final char PACKAGE_SEPARATOR_INTERNAL = '/'; + public static final char HIDDEN_SEPARATOR_INTERNAL = '.'; + public static final char PACKAGE_SEPARATOR_JAVA = HIDDEN_SEPARATOR_INTERNAL; + public static final char HIDDEN_SEPARATOR_JAVA = PACKAGE_SEPARATOR_INTERNAL; + /** * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for * anonymous and local classes. @@ -87,25 +92,27 @@ } /** - * Classes for lambdas can have {@code /} characters that are not package separators. These are - * distinguished by being followed by a character that is not a + * Hidden classes have {@code /} characters in their internal names and {@code .} characters in their names returned + * by {@link Class#getName()} that are not package separators. + * These are distinguished by being followed by a character that is not a * {@link Character#isJavaIdentifierStart(char)} (e.g., * "jdk.vm.ci.runtime.test.TypeUniverse$$Lambda$1/869601985"). + * + * @param name the name to perform the replacements on + * @param packageSeparator the {@link Character} used as the package separator, e.g. {@code /} in internal form + * @param hiddenSeparator the {@link Character} used as the hidden class separator, e.g. {@code .} in internal form */ - private static String replacePackageSeparatorsWithDot(String name) { + private static String replacePackageAndHiddenSeparators(String name, Character packageSeparator, Character hiddenSeparator) { + int index = name.indexOf(hiddenSeparator); // check if it's a hidden class int length = name.length(); - int i = 0; StringBuilder buf = new StringBuilder(length); - while (i < length - 1) { - char ch = name.charAt(i); - if (ch == '/' && Character.isJavaIdentifierStart(name.charAt(i + 1))) { - buf.append('.'); - } else { - buf.append(ch); - } - i++; + if (index < 0) { + buf.append(name.replace(packageSeparator, hiddenSeparator)); + } else { + buf.append(name.substring(0, index).replace(packageSeparator, hiddenSeparator)); + buf.append(packageSeparator); + buf.append(name.substring(index + 1)); } - buf.append(name.charAt(length - 1)); return buf.toString(); } @@ -122,9 +129,10 @@ public static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) { switch (name.charAt(0)) { case 'L': { - String result = replacePackageSeparatorsWithDot(name.substring(1, name.length() - 1)); + String type = name.substring(1, name.length() - 1); + String result = replacePackageAndHiddenSeparators(type, PACKAGE_SEPARATOR_INTERNAL, HIDDEN_SEPARATOR_INTERNAL); if (!qualified) { - final int lastDot = result.lastIndexOf('.'); + final int lastDot = result.lastIndexOf(HIDDEN_SEPARATOR_INTERNAL); if (lastDot != -1) { result = result.substring(lastDot + 1); } @@ -132,7 +140,11 @@ return result; } case '[': - return classForNameCompatible ? replacePackageSeparatorsWithDot(name) : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]"; + if (classForNameCompatible) { + return replacePackageAndHiddenSeparators(name, PACKAGE_SEPARATOR_INTERNAL, HIDDEN_SEPARATOR_INTERNAL); + } else { + return internalNameToJava(name.substring(1), qualified, false) + "[]"; + } default: if (name.length() != 1) { throw new IllegalArgumentException("Illegal internal name: " + name); @@ -213,7 +225,7 @@ public static String toInternalName(String className) { if (className.startsWith("[")) { /* Already in the correct array style. */ - return className.replace('.', '/'); + return replacePackageAndHiddenSeparators(className, PACKAGE_SEPARATOR_JAVA, HIDDEN_SEPARATOR_JAVA); } StringBuilder result = new StringBuilder(); @@ -252,7 +264,9 @@ result.append("V"); break; default: - result.append("L").append(base.replace('.', '/')).append(";"); + result.append("L") + .append(replacePackageAndHiddenSeparators(base, PACKAGE_SEPARATOR_JAVA, HIDDEN_SEPARATOR_JAVA)) + .append(";"); break; } return result.toString(); diff -Nru openjdk-17-17.0.3+7/src/jdk.jcmd/share/man/jcmd.1 openjdk-17-17.0.4+8/src/jdk.jcmd/share/man/jcmd.1 --- openjdk-17-17.0.3+7/src/jdk.jcmd/share/man/jcmd.1 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.jcmd/share/man/jcmd.1 2022-07-14 08:05:38.000000000 +0000 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. .\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. .\" .\" This code is free software; you can redistribute it and/or modify it @@ -764,6 +764,56 @@ (BOOLEAN, false) .RE .TP +.B \f[CB]VM.cds\f[R] [\f[I]arguments\f[R]] +Dumps a static or dynamic shared archive that includes all currently +loaded classes. +.RS +.PP +Impact: Medium \-\-\- pause time depends on number of loaded classes +.PP +Permission: \f[CB]java.lang.management.ManagementPermission(monitor)\f[R] +.PP +\f[I]arguments\f[R]: +.IP \[bu] 2 +\f[CB]subcmd\f[R]: must be either \f[CB]static_dump\f[R] or +.IP \[bu] 2 +\f[CB]filename\f[R]: (Optional) Name of the shared archive to be dumped +(STRING, no default value) +.PP +If \f[CB]filename\f[R] is not specified, a default file name is chosen +using the pid of the target JVM process. +For example, java_pid1234_static.jsa, java_pid5678_dynamic.jsa, etc. +.PP +If \f[CB]filename\f[R] is not specified as an absolute path, the archive +file is created in a directory relative to the current directory of the +target JVM process. +.RE +.TP +.B \f[CB]VM.classloaders\f[R] [\f[I]options\f[R]] +Prints classloader hierarchy. +.RS +.PP +Impact: Medium \-\-\- Depends on number of class loaders and classes +loaded. +.PP +Permission: \f[CB]java.lang.management.ManagementPermission(monitor)\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[CB]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[CB]show\-classes\f[R]: (Optional) Print loaded classes. +(BOOLEAN, false) +.IP \[bu] 2 +\f[CB]verbose\f[R]: (Optional) Print detailed information. +(BOOLEAN, false) +.IP \[bu] 2 +\f[CB]fold\f[R]: (Optional) Show loaders of the same name and class as +one. +(BOOLEAN, true) +.RE +.TP .B \f[CB]VM.classloader_stats\f[R] Prints statistics about all ClassLoaders. .RS diff -Nru openjdk-17-17.0.3+7/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java openjdk-17-17.0.4+8/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java --- openjdk-17-17.0.3+7/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java 2022-07-14 08:05:38.000000000 +0000 @@ -356,7 +356,8 @@ protected ClassFile readClassFile(JarFile jarfile, JarEntry e) throws IOException { try (InputStream is = jarfile.getInputStream(e)) { ClassFile cf = ClassFile.read(is); - if (jarfile.isMultiRelease()) { + // exclude module-info.class since this jarFile is on classpath + if (jarfile.isMultiRelease() && !cf.getName().equals("module-info")) { VersionHelper.add(jarfile, e, cf); } return cf; @@ -437,5 +438,4 @@ throw new UnsupportedOperationException("Not supported yet."); } } - private static final String MODULE_INFO = "module-info.class"; } diff -Nru openjdk-17-17.0.3+7/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java openjdk-17-17.0.4+8/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java --- openjdk-17-17.0.3+7/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java 2022-07-14 08:05:38.000000000 +0000 @@ -268,7 +268,14 @@ } return targets; } catch (InterruptedException|ExecutionException e) { - throw new Error(e); + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException x) { + throw x; + } else if (cause instanceof Error x) { + throw x; + } else { + throw new Error(e); + } } } diff -Nru openjdk-17-17.0.3+7/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java openjdk-17-17.0.4+8/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java --- openjdk-17-17.0.3+7/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java 2022-07-14 08:05:38.000000000 +0000 @@ -46,7 +46,7 @@ * The detail message array */ public MultiReleaseException(String key, Object... params) { - super(); + super(JdepsTask.getMessage(key, params)); this.key = key; this.params = params; } diff -Nru openjdk-17-17.0.3+7/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java openjdk-17-17.0.4+8/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java --- openjdk-17-17.0.3+7/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java 2022-07-14 08:05:38.000000000 +0000 @@ -55,15 +55,10 @@ String version = realName.substring(len, n); assert (Integer.parseInt(version) > 8); String name = cf.getName().replace('/', '.'); - if (nameToVersion.containsKey(name)) { - if (!version.equals(nameToVersion.get(name))) { - throw new MultiReleaseException( - "err.multirelease.version.associated", - name, nameToVersion.get(name), version - ); - } - } else { - nameToVersion.put(name, version); + String v = nameToVersion.computeIfAbsent(name, _n -> version); + if (!version.equals(v)) { + throw new MultiReleaseException("err.multirelease.version.associated", + name, nameToVersion.get(name), version); } } else { throw new MultiReleaseException("err.multirelease.jar.malformed", diff -Nru openjdk-17-17.0.3+7/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c openjdk-17-17.0.4+8/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c --- openjdk-17-17.0.3+7/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,14 +81,22 @@ struct bag * classTrack_processUnloads(JNIEnv *env) { - debugMonitorEnter(classTrackLock); if (deletedSignatures == NULL) { - // Class tracking not initialized, nobody's interested. - debugMonitorExit(classTrackLock); - return NULL; + return NULL; } + + /* Allocate new bag outside classTrackLock lock to avoid deadlock. + * + * Note: jvmtiAllocate/jvmtiDeallocate() may be blocked by ongoing safepoints. + * It is dangerous to call them (via bagCreateBag/bagDestroyBag()) while holding monitor(s), + * because jvmti may post events, e.g. JVMTI_EVENT_OBJECT_FREE at safepoints and event processing + * code may acquire the same monitor(s), e.g. classTrackLock in cbTrackingObjectFree(), + * which can lead to deadlock. + */ + struct bag* new_bag = bagCreateBag(sizeof(char*), 10); + debugMonitorEnter(classTrackLock); struct bag* deleted = deletedSignatures; - deletedSignatures = bagCreateBag(sizeof(char*), 10); + deletedSignatures = new_bag; debugMonitorExit(classTrackLock); return deleted; } @@ -194,8 +202,11 @@ void classTrack_activate(JNIEnv *env) { + // Allocate bag outside classTrackLock lock to avoid deadlock. + // See comments in classTrack_processUnloads() for details. + struct bag* new_bag = bagCreateBag(sizeof(char*), 1000); debugMonitorEnter(classTrackLock); - deletedSignatures = bagCreateBag(sizeof(char*), 1000); + deletedSignatures = new_bag; debugMonitorExit(classTrackLock); } @@ -214,12 +225,14 @@ classTrack_reset(void) { debugMonitorEnter(classTrackLock); + struct bag* to_delete = deletedSignatures; + deletedSignatures = NULL; + debugMonitorExit(classTrackLock); - if (deletedSignatures != NULL) { - bagEnumerateOver(deletedSignatures, cleanDeleted, NULL); - bagDestroyBag(deletedSignatures); - deletedSignatures = NULL; + // Deallocate bag outside classTrackLock to avoid deadlock. + // See comments in classTrack_processUnloads() for details. + if (to_delete != NULL) { + bagEnumerateOver(to_delete, cleanDeleted, NULL); + bagDestroyBag(to_delete); } - - debugMonitorExit(classTrackLock); } diff -Nru openjdk-17-17.0.3+7/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c openjdk-17-17.0.4+8/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c --- openjdk-17-17.0.3+7/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c 2022-07-14 08:05:38.000000000 +0000 @@ -232,6 +232,7 @@ /* * Squirrel away the method signature */ + JDI_ASSERT_MSG(request->methodSignature == NULL, "Request methodSignature not null"); error = methodSignature(method, NULL, &request->methodSignature, NULL); if (error != JVMTI_ERROR_NONE) { return error; @@ -773,6 +774,10 @@ */ deleteGlobalArgumentRefs(env, request); + JDI_ASSERT_MSG(request->methodSignature != NULL, "methodSignature is NULL"); + jvmtiDeallocate(request->methodSignature); + request->methodSignature = NULL; + /* From now on, do not access the request structure anymore * for this request id, because once we give up the invokerLock it may * be immediately reused by a new invoke request. @@ -791,6 +796,7 @@ (void)outStream_writeObjectTag(env, &out, exc); (void)outStream_writeObjectRef(env, &out, exc); outStream_sendReply(&out); + outStream_destroy(&out); } /* diff -Nru openjdk-17-17.0.3+7/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c openjdk-17-17.0.4+8/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c --- openjdk-17-17.0.3+7/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c 2022-07-14 08:05:38.000000000 +0000 @@ -73,6 +73,7 @@ unsigned int popFrameEvent : 1; unsigned int popFrameProceed : 1; unsigned int popFrameThread : 1; + unsigned int handlingAppResume : 1; EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */ jobject pendingStop; /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */ jint suspendCount; @@ -655,7 +656,10 @@ if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "getting thread state"); } - if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) { + /* !node->handlingAppResume && resumeFrameDepth > 0 + * means the thread has entered Thread.resume() */ + if (!(state & JVMTI_THREAD_STATE_SUSPENDED) && + !node->handlingAppResume) { return JNI_TRUE; } } @@ -728,6 +732,11 @@ } } +/* + * The caller is expected to hold threadLock and handlerLock. + * eventHandler_createInternalThreadOnly() can deadlock because of + * wrong lock ordering if the caller does not hold handlerLock. + */ static void trackAppResume(jthread thread) { @@ -776,28 +785,19 @@ struct bag *eventBag) { jthread resumer = evinfo->thread; - jthread resumee = getResumee(resumer); debugMonitorEnter(threadLock); - if (resumee != NULL) { - /* - * Hold up any attempt to resume as long as the debugger - * has suspended the resumee. - */ - blockOnDebuggerSuspend(resumee); - } + /* + * Actual handling has to be deferred. We cannot block right here if the + * target of the resume call is suspended by the debugger since we are + * holding handlerLock which must not be released. See doPendingTasks(). + */ if (resumer != NULL) { - /* - * Track the resuming thread by marking it as being within - * a resume and by setting up for notification on - * a frame pop or exception. We won't allow the debugger - * to suspend threads while any thread is within a - * call to resume. This (along with the block above) - * ensures that when the debugger - * suspends a thread it will remain suspended. - */ - trackAppResume(resumer); + ThreadNode* node = findThread(&runningThreads, resumer); + if (node != NULL) { + node->handlingAppResume = JNI_TRUE; + } } debugMonitorExit(threadLock); @@ -2155,6 +2155,59 @@ static void doPendingTasks(JNIEnv *env, ThreadNode *node) { + /* Deferred breakpoint handling for Thread.resume() */ + if (node->handlingAppResume) { + jthread resumer = node->thread; + jthread resumee = getResumee(resumer); + + if (resumer != NULL) { + /* + * trackAppResume indirectly aquires handlerLock. For proper lock + * ordering handlerLock has to be acquired before threadLock. + */ + debugMonitorExit(threadLock); + eventHandler_lock(); + debugMonitorEnter(threadLock); + + /* + * Track the resuming thread by marking it as being within + * a resume and by setting up for notification on + * a frame pop or exception. We won't allow the debugger + * to suspend threads while any thread is within a + * call to resume. This (along with the block below) + * ensures that when the debugger + * suspends a thread it will remain suspended. + */ + trackAppResume(resumer); + + /* + * handlerLock is not needed anymore. We must release it before calling + * blockOnDebuggerSuspend() because it is required for resumes done by + * the debugger. If resumee is currently suspended by the debugger, then + * blockOnDebuggerSuspend() will block until a debugger resume is done. + * If it blocks while holding the handlerLock, then the resume will deadlock. + */ + eventHandler_unlock(); + } + + if (resumee != NULL) { + /* + * Hold up any attempt to resume as long as the debugger + * has suspended the resumee. + */ + blockOnDebuggerSuspend(resumee); + } + + node->handlingAppResume = JNI_FALSE; + + /* + * The blocks exit condition: resumee's suspendCount == 0. + * + * Debugger suspends are blocked if any thread is executing + * Thread.resume(), i.e. !handlingAppResume && frameDepth > 0. + */ + } + /* * Take care of any pending interrupts/stops, and clear out * info on pending interrupts/stops. @@ -2455,6 +2508,8 @@ /* Everything should have been resumed */ JDI_ASSERT(otherThreads.first == NULL); + /* Threads could be waiting in blockOnDebuggerSuspend */ + debugMonitorNotifyAll(threadLock); debugMonitorExit(threadLock); eventHandler_unlock(); } diff -Nru openjdk-17-17.0.3+7/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java openjdk-17-17.0.4+8/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java --- openjdk-17-17.0.3+7/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.random/share/classes/jdk/random/L32X64MixRandom.java 2022-07-14 08:05:38.000000000 +0000 @@ -155,6 +155,8 @@ // Force a to be odd. this.a = a | 1; this.s = s; + this.x0 = x0; + this.x1 = x1; // If x0 and x1 are both zero, we must choose nonzero values. if ((x0 | x1) == 0) { int v = s; diff -Nru openjdk-17-17.0.3+7/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java openjdk-17-17.0.4+8/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java --- openjdk-17-17.0.3+7/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java 2022-07-14 08:05:38.000000000 +0000 @@ -151,9 +151,9 @@ this.forceEnd64 = isTrue(env, "forceZIP64End"); this.defaultCompressionMethod = getDefaultCompressionMethod(env); this.supportPosix = isTrue(env, PROPERTY_POSIX); - this.defaultOwner = initOwner(zfpath, env); - this.defaultGroup = initGroup(zfpath, env); - this.defaultPermissions = initPermissions(env); + this.defaultOwner = supportPosix ? initOwner(zfpath, env) : null; + this.defaultGroup = supportPosix ? initGroup(zfpath, env) : null; + this.defaultPermissions = supportPosix ? initPermissions(env) : null; this.supportedFileAttributeViews = supportPosix ? Set.of("basic", "posix", "zip") : Set.of("basic", "zip"); if (Files.notExists(zfpath)) { @@ -1575,9 +1575,9 @@ throw new ZipException("invalid CEN header (bad header size)"); } IndexNode inode = new IndexNode(cen, pos, nlen); - if (hasDotOrDotDot(inode.name)) { + if (inode.pathHasDotOrDotDot()) { throw new ZipException("ZIP file can't be opened as a file system " + - "because an entry has a '.' or '..' element in its name"); + "because entry \"" + inode.nameAsString() + "\" has a '.' or '..' element in its name"); } inodes.put(inode, inode); if (zc.isUTF8() || (flag & FLAG_USE_UTF8) != 0) { @@ -1595,44 +1595,6 @@ return cen; } - /** - * Check Inode.name to see if it includes a "." or ".." in the name array - * @param path the path as stored in Inode.name to verify - * @return true if the path contains a "." or ".." entry; false otherwise - */ - private boolean hasDotOrDotDot(byte[] path) { - // Inode.name always includes "/" in path[0] - assert path[0] == '/'; - if (path.length == 1) { - return false; - } - int index = 1; - while (index < path.length) { - int starting = index; - while (index < path.length && path[index] != '/') { - index++; - } - // Check the path snippet for a "." or ".." - if (isDotOrDotDotPath(path, starting, index)) { - return true; - } - index++; - } - return false; - } - - /** - * Check the path to see if it includes a "." or ".." - * @param path the path to check - * @return true if the path contains a "." or ".." entry; false otherwise - */ - private boolean isDotOrDotDotPath(byte[] path, int start, int index) { - int pathLen = index - start; - if ((pathLen == 1 && path[start] == '.')) - return true; - return (pathLen == 2 && path[start] == '.') && path[start + 1] == '.'; - } - private final void checkUTF8(byte[] a) throws ZipException { try { int end = a.length; @@ -2653,6 +2615,37 @@ return isdir; } + /** + * Check name if it contains a "." or ".." path element + * @return true if the path contains a "." or ".." entry; false otherwise + */ + private boolean pathHasDotOrDotDot() { + // name always includes "/" in path[0] + assert name[0] == '/'; + if (name.length == 1) { + return false; + } + int index = 1; + while (index < name.length) { + int start = index; + while (index < name.length && name[index] != '/') { + index++; + } + if (name[start] == '.') { + int len = index - start; + if (len == 1 || (name[start + 1] == '.' && len == 2)) { + return true; + } + } + index++; + } + return false; + } + + protected String nameAsString() { + return new String(name); + } + @Override public boolean equals(Object other) { if (!(other instanceof IndexNode)) { @@ -2671,7 +2664,7 @@ @Override public String toString() { - return new String(name) + (isdir ? " (dir)" : " ") + ", index: " + pos; + return nameAsString() + (isdir ? " (dir)" : " ") + ", index: " + pos; } } @@ -3207,7 +3200,7 @@ public String toString() { StringBuilder sb = new StringBuilder(1024); Formatter fm = new Formatter(sb); - fm.format(" name : %s%n", new String(name)); + fm.format(" name : %s%n", nameAsString()); fm.format(" creationTime : %tc%n", creationTime().toMillis()); fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis()); fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis()); diff -Nru openjdk-17-17.0.3+7/test/hotspot/gtest/logging/test_logConfiguration.cpp openjdk-17-17.0.4+8/test/hotspot/gtest/logging/test_logConfiguration.cpp --- openjdk-17-17.0.3+7/test/hotspot/gtest/logging/test_logConfiguration.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/gtest/logging/test_logConfiguration.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -359,6 +359,29 @@ ret = jio_snprintf(buf, sizeof(buf), ":%s", TestLogFileName); ASSERT_NE(-1, ret); EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf)); + +#ifdef _WINDOWS + // We need to test the special-case parsing for drive letters in + // log file paths e.g. c:\log.txt and c:/log.txt. Our temp directory + // based TestLogFileName should already be the \ format (we print it + // below to visually verify) so we only need to convert to /. + printf("Checked: %s\n", buf); + // First disable logging so the current log file will be closed and we + // can delete it, so that UL won't try to perform log file rotation. + // The rotated file would not be auto-deleted. + set_log_config(TestLogFileName, "all=off"); + delete_file(TestLogFileName); + + // now convert \ to / + char* current_pos = strchr(buf,'\\'); + while (current_pos != nullptr) { + *current_pos = '/'; + current_pos = strchr(current_pos + 1, '\\'); + } + printf("Checking: %s\n", buf); + EXPECT_TRUE(LogConfiguration::parse_command_line_arguments(buf)); +#endif + } // Test split up log configuration arguments diff -Nru openjdk-17-17.0.3+7/test/hotspot/gtest/runtime/test_os.cpp openjdk-17-17.0.4+8/test/hotspot/gtest/runtime/test_os.cpp --- openjdk-17-17.0.3+7/test/hotspot/gtest/runtime/test_os.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/gtest/runtime/test_os.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -26,6 +26,7 @@ #include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" +#include "services/memTracker.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" @@ -417,9 +418,33 @@ #else TEST_VM(os, release_multi_mappings) { #endif + + // With NMT enabled, this will trigger JDK-8263464. For now disable the test if NMT=on. + if (MemTracker::tracking_level() > NMT_off) { + return; + } + // Test that we can release an area created with multiple reservation calls - const size_t stripe_len = 4 * M; - const int num_stripes = 4; + // What we do: + // A) we reserve 6 small segments (stripes) adjacent to each other. We commit + // them with alternating permissions to prevent the kernel from folding them into + // a single segment. + // -stripe-stripe-stripe-stripe-stripe-stripe- + // B) we release the middle four stripes with a single os::release_memory call. This + // tests that os::release_memory indeed works across multiple segments created with + // multiple os::reserve calls. + // -stripe-___________________________-stripe- + // C) Into the now vacated address range between the first and the last stripe, we + // re-reserve a new memory range. We expect this to work as a proof that the address + // range was really released by the single release call (B). + // + // Note that this is inherently racy. Between (B) and (C), some other thread may have + // reserved something into the hole in the meantime. Therefore we keep that range small and + // entrenched between the first and last stripe, which reduces the chance of some concurrent + // thread grabbing that memory. + + const size_t stripe_len = os::vm_allocation_granularity(); + const int num_stripes = 6; const size_t total_range_len = stripe_len * num_stripes; // reserve address space... @@ -427,22 +452,27 @@ ASSERT_NE(p, (address)NULL); PRINT_MAPPINGS("A"); - // .. release it... + // .. release the middle stripes... + address p_middle_stripes = p + stripe_len; + const size_t middle_stripe_len = (num_stripes - 2) * stripe_len; { - // On Windows, use UseNUMAInterleaving=1 which makes - // os::release_memory accept multi-map-ranges. - // Otherwise we would assert (see below for death test). + // On Windows, temporarily switch on UseNUMAInterleaving to allow release_memory to release + // multiple mappings in one go (otherwise we assert, which we test too, see death test below). WINDOWS_ONLY(NUMASwitcher b(true);) - ASSERT_TRUE(os::release_memory((char*)p, total_range_len)); + ASSERT_TRUE(os::release_memory((char*)p_middle_stripes, middle_stripe_len)); } PRINT_MAPPINGS("B"); - // re-reserve it. This should work unless release failed. - address p2 = (address)os::attempt_reserve_memory_at((char*)p, total_range_len); - ASSERT_EQ(p2, p); + // ...re-reserve the middle stripes. This should work unless release silently failed. + address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len); + ASSERT_EQ(p2, p_middle_stripes); PRINT_MAPPINGS("C"); - ASSERT_TRUE(os::release_memory((char*)p, total_range_len)); + // Clean up. Release all mappings. + { + WINDOWS_ONLY(NUMASwitcher b(true);) // allow release_memory to release multiple regions + ASSERT_TRUE(os::release_memory((char*)p, total_range_len)); + } } #endif // !AIX diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8279125 + * @summary fatal error: no reachable node should have no use + * @requires vm.flavor == "server" + * + * @run main/othervm -XX:-BackgroundCompilation -XX:-DoEscapeAnalysis TestAllocArrayAfterAllocNoUse + * + */ + +public class TestAllocArrayAfterAllocNoUse { + private static Object field; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(); + } + } + + private static void test() { + try { + final TestAllocArrayAfterAllocNoUse o = new TestAllocArrayAfterAllocNoUse(); + } catch (Exception e) { + final int[] array = new int[100]; + field = array; + } + + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8279062 + * @summary C2: assert(t->meet(t0) == t) failed: Not monotonic after JDK-8278413 + * + * @run main/othervm -XX:-BackgroundCompilation TestCCPAllocateArray + * + */ + +public class TestCCPAllocateArray { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + try { + test(); + } catch (OutOfMemoryError e) { + } + length(42); + } + } + + private static int[] test() { + int i = 2; + for (; i < 4; i *= 2); + return new int[length(i)]; + } + + private static int length(int i) { + return i == 4 ? Integer.MAX_VALUE : 0; + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 8279219 + * @summary C2 crash when allocating array of size too large + * @requires vm.compiler2.enabled + * @library /test/lib / + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -ea -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestFailedAllocationBadGraph + */ + +import sun.hotspot.WhiteBox; +import java.lang.reflect.Method; +import compiler.whitebox.CompilerWhiteBoxTest; + +public class TestFailedAllocationBadGraph { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static long[] array; + private static int field; + private static volatile int barrier; + + public static void main(String[] args) throws Exception { + run("test1"); + run("test2"); + } + + private static void run(String method) throws Exception { + Method m = TestFailedAllocationBadGraph.class.getDeclaredMethod(method); + WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + if (!WHITE_BOX.isMethodCompiled(m) || WHITE_BOX.getMethodCompilationLevel(m) != CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) { + throw new RuntimeException("should still be compiled"); + } + } + + private static int test1() { + int length = Integer.MAX_VALUE; + try { + array = new long[length]; + } catch (OutOfMemoryError outOfMemoryError) { + barrier = 0x42; + length = field; + } + return length; + } + + private static int test2() { + int length = -1; + try { + array = new long[length]; + } catch (OutOfMemoryError outOfMemoryError) { + barrier = 0x42; + length = field; + } + return length; + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/AbstractStressArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/AbstractStressArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/AbstractStressArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/AbstractStressArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Random; + +public abstract class AbstractStressArrayCopy { + /** + * Max array size to test. This should be reasonably high to test + * massive vectorized copies, plus cases that cross the cache lines and + * (small) page boundaries. But it should also be reasonably low to + * keep the test costs down. + * + * A rough guideline: + * - AVX-512: 64-byte copies over 32 registers copies roughly 2K per step. + * - AArch64: small pages can be about 64K large + */ + static final int MAX_SIZE = 128*1024 + 1; + + /** + * Arrays up to this size would be tested exhaustively: with all combinations + * of source/destination starts and copy lengths. Exercise restraint when bumping + * this value, as the test costs are proportional to N^3 of this setting. + */ + static final int EXHAUSTIVE_SIZES = Integer.getInteger("exhaustiveSizes", 192); + + /* + * Larger arrays would fuzzed with this many attempts. + */ + static final int FUZZ_COUNT = Integer.getInteger("fuzzCount", 300); + + public static void throwSeedError(int len, int pos) { + throw new RuntimeException("Error after seed: " + + len + " elements, at pos " + pos); + } + + public static void throwContentsError(int l, int r, int len, int pos) { + throwError("in contents", l, r, len, pos); + } + + public static void throwHeadError(int l, int r, int len, int pos) { + throwError("in head", l, r, len, pos); + } + + public static void throwTailError(int l, int r, int len, int pos) { + throwError("in tail", l, r, len, pos); + } + + private static void throwError(String phase, int l, int r, int len, int pos) { + throw new RuntimeException("Error " + phase + ": " + + len + " elements, " + + "[" + l + ", " + (l+len) + ") -> " + + "[" + r + ", " + (r+len) + "), " + + "at pos " + pos); + } + + protected abstract void testWith(int size, int l, int r, int len); + + private void checkBounds(int size, int l, int r, int len) { + if (l >= size) throw new IllegalStateException("l is out of bounds"); + if (l + len > size) throw new IllegalStateException("l+len is out of bounds"); + if (r >= size) throw new IllegalStateException("r is out of bounds"); + if (r + len > size) throw new IllegalStateException("r+len is out of bounds: " + l + " " + r + " " + len + " " + size); + } + + private void checkDisjoint(int size, int l, int r, int len) { + if (l == r) throw new IllegalStateException("Not disjoint: l == r"); + if (l < r && l + len > r) throw new IllegalStateException("Not disjoint"); + if (l > r && r + len > l) throw new IllegalStateException("Not disjoint"); + } + + private void checkConjoint(int size, int l, int r, int len) { + if (l == r) return; // Definitely conjoint, even with zero len + if (l < r && l + len < r) throw new IllegalStateException("Not conjoint"); + if (l > r && r + len < l) throw new IllegalStateException("Not conjoint"); + } + + public void exhaustiveWith(int size) { + for (int l = 0; l < size; l++) { + for (int r = 0; r < size; r++) { + int maxLen = Math.min(size - l, size - r); + for (int len = 0; len <= maxLen; len++) { + checkBounds(size, l, r, len); + testWith(size, l, r, len); + } + } + } + } + + public void fuzzWith(Random rand, int size) { + // Some basic checks first + testWith(size, 0, 1, 1); + testWith(size, 0, 1, size-1); + + // Test disjoint: + for (int c = 0; c < FUZZ_COUNT; c++) { + int l = rand.nextInt(size / 2); + int len = rand.nextInt((size - l) / 2); + int r = (l + len + 1) + rand.nextInt(size - 2*len - l - 1); + + checkBounds(size, l, r, len); + checkDisjoint(size, l, r, len); + + testWith(size, l, r, len); + testWith(size, r, l, len); + } + + // Test conjoint: + for (int c = 0; c < FUZZ_COUNT; c++) { + int l = rand.nextInt(size); + int len = rand.nextInt(size - l); + int r = Math.min(l + (len > 0 ? rand.nextInt(len) : 0), size - len); + + checkBounds(size, l, r, len); + checkConjoint(size, l, r, len); + + testWith(size, l, r, len); + testWith(size, r, l, len); + } + } + + public void run(Random rand) { + // Exhaustive on all small arrays + for (int size = 1; size <= EXHAUSTIVE_SIZES; size++) { + exhaustiveWith(size); + } + + // Fuzz powers of ten + for (int size = 10; size < MAX_SIZE; size *= 10) { + if (size <= EXHAUSTIVE_SIZES) continue; + fuzzWith(rand, size - 1); + fuzzWith(rand, size); + fuzzWith(rand, size + 1); + } + + // Fuzz powers of two + for (int size = 2; size < MAX_SIZE; size *= 2) { + if (size <= EXHAUSTIVE_SIZES) continue; + fuzzWith(rand, size - 1); + fuzzWith(rand, size); + fuzzWith(rand, size + 1); + } + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressBooleanArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressBooleanArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressBooleanArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressBooleanArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressBooleanArrayCopy extends AbstractStressArrayCopy { + + private static final boolean[] orig = new boolean[MAX_SIZE]; + private static final boolean[] test = new boolean[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextBoolean(); + } + new StressBooleanArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressByteArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressByteArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressByteArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressByteArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressByteArrayCopy extends AbstractStressArrayCopy { + + private static final byte[] orig = new byte[MAX_SIZE]; + private static final byte[] test = new byte[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = (byte)rand.nextInt(); + } + new StressByteArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressCharArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressCharArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressCharArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressCharArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressCharArrayCopy extends AbstractStressArrayCopy { + + private static final char[] orig = new char[MAX_SIZE]; + private static final char[] test = new char[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = (char)rand.nextInt(); + } + new StressCharArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressDoubleArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressDoubleArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressDoubleArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressDoubleArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressDoubleArrayCopy extends AbstractStressArrayCopy { + + private static final double[] orig = new double[MAX_SIZE]; + private static final double[] test = new double[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextDouble(); + } + new StressDoubleArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressFloatArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressFloatArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressFloatArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressFloatArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressFloatArrayCopy extends AbstractStressArrayCopy { + + private static final float[] orig = new float[MAX_SIZE]; + private static final float[] test = new float[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextFloat(); + } + new StressFloatArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressIntArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressIntArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressIntArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressIntArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressIntArrayCopy extends AbstractStressArrayCopy { + + private static final int[] orig = new int[MAX_SIZE]; + private static final int[] test = new int[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextInt(); + } + new StressIntArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressLongArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressLongArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressLongArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressLongArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressLongArrayCopy extends AbstractStressArrayCopy { + + private static final long[] orig = new long[MAX_SIZE]; + private static final long[] test = new long[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = rand.nextLong(); + } + new StressLongArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressObjectArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressObjectArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressObjectArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressObjectArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressObjectArrayCopy extends AbstractStressArrayCopy { + + private static final Object[] orig = new Object[MAX_SIZE]; + private static final Object[] test = new Object[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = new Object(); + } + new StressObjectArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressShortArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressShortArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/StressShortArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/StressShortArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.Arrays; +import java.util.Random; +import jdk.test.lib.Utils; + +public class StressShortArrayCopy extends AbstractStressArrayCopy { + + private static final short[] orig = new short[MAX_SIZE]; + private static final short[] test = new short[MAX_SIZE]; + + protected void testWith(int size, int l, int r, int len) { + // Seed the test from the original + System.arraycopy(orig, 0, test, 0, size); + + // Check the seed is correct + { + int m = Arrays.mismatch(test, 0, size, + orig, 0, size); + if (m != -1) { + throwSeedError(size, m); + } + } + + // Perform the tested copy + System.arraycopy(test, l, test, r, len); + + // Check the copy has proper contents + { + int m = Arrays.mismatch(test, r, r+len, + orig, l, l+len); + if (m != -1) { + throwContentsError(l, r, len, r+m); + } + } + + // Check anything else was not affected: head and tail + { + int m = Arrays.mismatch(test, 0, r, + orig, 0, r); + if (m != -1) { + throwHeadError(l, r, len, m); + } + } + { + int m = Arrays.mismatch(test, r + len, size, + orig, r + len, size); + if (m != -1) { + throwTailError(l, r, len, m); + } + } + } + + public static void main(String... args) { + Random rand = Utils.getRandomInstance(); + for (int c = 0; c < orig.length; c++) { + orig[c] = (short)rand.nextInt(); + } + new StressShortArrayCopy().run(rand); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arraycopy.stress; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import jdk.test.whitebox.cpuinfo.CPUInfo; + +/** + * @test + * @key stress randomness + * @library /test/lib + * @build compiler.arraycopy.stress.AbstractStressArrayCopy + * compiler.arraycopy.stress.StressBooleanArrayCopy + * compiler.arraycopy.stress.StressByteArrayCopy + * compiler.arraycopy.stress.StressCharArrayCopy + * compiler.arraycopy.stress.StressShortArrayCopy + * compiler.arraycopy.stress.StressIntArrayCopy + * compiler.arraycopy.stress.StressFloatArrayCopy + * compiler.arraycopy.stress.StressLongArrayCopy + * compiler.arraycopy.stress.StressDoubleArrayCopy + * compiler.arraycopy.stress.StressObjectArrayCopy + * jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm/timeout=7200 + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.arraycopy.stress.TestStressArrayCopy + */ +public class TestStressArrayCopy { + + // These tests are remarkably memory bandwidth hungry. Running multiple + // configs in parallel makes sense only when running a single test in + // isolation, and only on machines with many memory channels. In common + // testing, or even running all arraycopy stress tests at once, overloading + // the system with many configs become counter-productive very quickly. + // + // Default to 1/4 of the CPUs, and allow users to override. + static final int MAX_PARALLELISM = Integer.getInteger("maxParallelism", + Math.max(1, Runtime.getRuntime().availableProcessors() / 4)); + + private static List mix(List o, String... mix) { + List n = new ArrayList<>(o); + for (String m : mix) { + n.add(m); + } + return n; + } + + private static List> product(List> list, String... mix) { + List> newList = new ArrayList<>(); + for (List c : list) { + for (String m : mix) { + newList.add(mix(c, m)); + } + } + return newList; + } + + private static List> alternate(List> list, String opt) { + return product(list, "-XX:+" + opt, "-XX:-" + opt); + } + + private static boolean containsFuzzy(List list, String sub) { + for (String s : list) { + if (s.contains(sub)) return true; + } + return false; + } + + public static void main(String... args) throws Exception { + List> configs = new ArrayList<>(); + List cpuFeatures = CPUInfo.getFeatures(); + + if (Platform.isX64() || Platform.isX86()) { + // If CPU features were not found, provide a default config. + if (cpuFeatures.isEmpty()) { + configs.add(new ArrayList()); + } + + // Otherwise, select the tests that make sense on current platform. + if (containsFuzzy(cpuFeatures, "avx512")) { + configs.add(List.of("-XX:UseAVX=3")); + } + if (containsFuzzy(cpuFeatures, "avx2")) { + configs.add(List.of("-XX:UseAVX=2")); + } + if (containsFuzzy(cpuFeatures, "avx")) { + configs.add(List.of("-XX:UseAVX=1")); + } + if (containsFuzzy(cpuFeatures, "sse4")) { + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=4")); + } + if (containsFuzzy(cpuFeatures, "sse3")) { + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=3")); + } + if (containsFuzzy(cpuFeatures, "sse2")) { + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=2")); + } + + // x86_64 always has UseSSE >= 2. These lower configurations only + // make sense for x86_32. + if (Platform.isX86()) { + if (containsFuzzy(cpuFeatures, "sse")) { + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=1")); + } + + configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=0")); + } + + // Alternate configs with other flags + if (Platform.isX64()) { + configs = alternate(configs, "UseCompressedOops"); + } + configs = alternate(configs, "UseUnalignedLoadStores"); + + } else if (Platform.isAArch64()) { + // AArch64. + configs.add(new ArrayList()); + + // Alternate configs with other flags + configs = alternate(configs, "UseCompressedOops"); + configs = alternate(configs, "UseSIMDForMemoryOps"); + } else { + // Generic config. + configs.add(new ArrayList()); + } + + String[] classNames = { + "compiler.arraycopy.stress.StressBooleanArrayCopy", + "compiler.arraycopy.stress.StressByteArrayCopy", + "compiler.arraycopy.stress.StressCharArrayCopy", + "compiler.arraycopy.stress.StressShortArrayCopy", + "compiler.arraycopy.stress.StressIntArrayCopy", + "compiler.arraycopy.stress.StressFloatArrayCopy", + "compiler.arraycopy.stress.StressLongArrayCopy", + "compiler.arraycopy.stress.StressDoubleArrayCopy", + "compiler.arraycopy.stress.StressObjectArrayCopy", + }; + + ArrayList forks = new ArrayList<>(); + int jobs = 0; + + for (List c : configs) { + for (String className : classNames) { + // Start a new job + { + ProcessBuilder pb = ProcessTools.createTestJvm(mix(c, "-Xmx256m", className)); + Process p = pb.start(); + OutputAnalyzer oa = new OutputAnalyzer(p); + forks.add(new Fork(p, oa)); + jobs++; + } + + // Wait for the completion of other jobs + while (jobs >= MAX_PARALLELISM) { + Fork f = findDone(forks); + if (f != null) { + OutputAnalyzer oa = f.oa(); + oa.shouldHaveExitValue(0); + forks.remove(f); + jobs--; + } else { + // Nothing is done, wait a little. + Thread.sleep(200); + } + } + } + } + + // Drain the rest + for (Fork f : forks) { + OutputAnalyzer oa = f.oa(); + oa.shouldHaveExitValue(0); + } + } + + private static Fork findDone(List forks) { + for (Fork f : forks) { + if (!f.p().isAlive()) { + return f; + } + } + return null; + } + + private static record Fork(Process p, OutputAnalyzer oa) {}; + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java 2022-07-14 08:05:38.000000000 +0000 @@ -38,6 +38,19 @@ * compiler.arraycopy.TestArrayCopyAsLoadsStores */ +/* + * @test + * @bug 8282590 + * @library / + * + * @run main/othervm -ea -XX:-BackgroundCompilation -XX:-UseOnStackReplacement + * -XX:CompileCommand=dontinline,compiler.arraycopy.TestArrayCopyAsLoadsStores::m* + * -XX:TypeProfileLevel=200 + * -XX:+IgnoreUnrecognizedVMOptions -XX:+StressArrayCopyMacroNode + * -XX:-TieredCompilation -XX:+StressReflectiveCode -XX:-ReduceInitialCardMarks + * compiler.arraycopy.TestArrayCopyAsLoadsStores + */ + package compiler.arraycopy; import java.util.Arrays; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @test * @bug 8248791 * @summary Test cloning with more than 8 (=ArrayCopyLoadStoreMaxElem) where loads are wrongly replaced by zero. + * @requires vm.compiler2.enabled | vm.graal.enabled + * * @run main/othervm -XX:-ReduceBulkZeroing * -XX:CompileCommand=dontinline,compiler.arraycopy.TestCloneAccess::* * compiler.arraycopy.TestCloneAccess diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccessStressGCM.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccessStressGCM.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccessStressGCM.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccessStressGCM.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8235332 8248226 * @summary Test cloning with more than 8 (=ArrayCopyLoadStoreMaxElem) fields with StressGCM * @library / + * @requires vm.compiler2.enabled | vm.graal.enabled * * @run main/othervm -Xbatch * -XX:CompileCommand=dontinline,compiler.arraycopy.TestCloneAccessStressGCM::test diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/blackhole/BlackholeIntrinsicTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/blackhole/BlackholeIntrinsicTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/blackhole/BlackholeIntrinsicTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/blackhole/BlackholeIntrinsicTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -77,6 +77,15 @@ TESTS.put("bh_s_long_2", BlackholeIntrinsicTest::test_long_2); TESTS.put("bh_s_double_2", BlackholeIntrinsicTest::test_double_2); TESTS.put("bh_s_Object_2", BlackholeIntrinsicTest::test_Object_2); + + // Test calling static methods through instance method to exercise + // unusual intrinsic shapes. + TESTS.put("bh_is_int_0", BlackholeIntrinsicTest::test_is_int_0); + TESTS.put("bh_is_Object_0", BlackholeIntrinsicTest::test_is_Object_0); + TESTS.put("bh_is_int_1", BlackholeIntrinsicTest::test_is_int_1); + TESTS.put("bh_is_Object_1", BlackholeIntrinsicTest::test_is_Object_1); + TESTS.put("bh_is_int_2", BlackholeIntrinsicTest::test_is_int_2); + TESTS.put("bh_is_Object_2", BlackholeIntrinsicTest::test_is_Object_2); } private static final int CYCLES = 100_000; @@ -162,6 +171,13 @@ } } + private static void test_is_int_0() { + BlackholeTarget t = new BlackholeTarget(); + for (int c = 0; c < CYCLES; c++) { + t.bh_is_int_0(); + } + } + private static void test_float_0() { for (int c = 0; c < CYCLES; c++) { BlackholeTarget.bh_s_float_0(); @@ -186,6 +202,13 @@ } } + private static void test_is_Object_0() { + BlackholeTarget t = new BlackholeTarget(); + for (int c = 0; c < CYCLES; c++) { + t.bh_is_Object_0(); + } + } + private static void test_boolean_1() { for (int c = 0; c < CYCLES; c++) { BlackholeTarget.bh_s_boolean_1((c & 0x1) == 0); @@ -216,6 +239,13 @@ } } + private static void test_is_int_1() { + BlackholeTarget t = new BlackholeTarget(); + for (int c = 0; c < CYCLES; c++) { + t.bh_is_int_1(c); + } + } + private static void test_float_1() { for (int c = 0; c < CYCLES; c++) { BlackholeTarget.bh_s_float_1(c); @@ -241,6 +271,14 @@ } } + private static void test_is_Object_1() { + BlackholeTarget t = new BlackholeTarget(); + for (int c = 0; c < CYCLES; c++) { + Object o = new Object(); + t.bh_is_Object_1(o); + } + } + private static void test_boolean_2() { for (int c = 0; c < CYCLES; c++) { BlackholeTarget.bh_s_boolean_2((c & 0x1) == 0, (c & 0x2) == 0); @@ -271,6 +309,13 @@ } } + private static void test_is_int_2() { + BlackholeTarget t = new BlackholeTarget(); + for (int c = 0; c < CYCLES; c++) { + t.bh_is_int_2(c, c + 1); + } + } + private static void test_float_2() { for (int c = 0; c < CYCLES; c++) { BlackholeTarget.bh_s_float_2(c, c + 1); @@ -296,4 +341,13 @@ BlackholeTarget.bh_s_Object_2(o1, o2); } } + + private static void test_is_Object_2() { + BlackholeTarget t = new BlackholeTarget(); + for (int c = 0; c < CYCLES; c++) { + Object o1 = new Object(); + Object o2 = new Object(); + t.bh_is_Object_2(o1, o2); + } + } } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/blackhole/BlackholeTarget.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/blackhole/BlackholeTarget.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/blackhole/BlackholeTarget.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/blackhole/BlackholeTarget.java 2022-07-14 08:05:38.000000000 +0000 @@ -48,6 +48,9 @@ public static void bh_s_double_0() {} public static void bh_s_Object_0() {} + public static void bh_is_int_0() {} + public static void bh_is_Object_0() {} + public static void bh_s_boolean_1(boolean v) {} public static void bh_s_byte_1(byte v) {} public static void bh_s_short_1(short v) {} @@ -58,6 +61,9 @@ public static void bh_s_double_1(double v) {} public static void bh_s_Object_1(Object v) {} + public static void bh_is_int_1(int v) {} + public static void bh_is_Object_1(Object v) {} + public static void bh_s_boolean_1_delegate(boolean v) { bh_s_boolean_1(v); } public static void bh_s_byte_1_delegate(byte v) { bh_s_byte_1(v); } public static void bh_s_short_1_delegate(short v) { bh_s_short_1(v); } @@ -78,6 +84,9 @@ public static void bh_s_double_2(double v1, double v2) {} public static void bh_s_Object_2(Object v1, Object v2) {} + public static void bh_is_int_2(int v1, int v2) {} + public static void bh_is_Object_2(Object v1, Object v2) {} + public static boolean bh_sr_boolean(boolean v) { return false; } public static byte bh_sr_byte(byte v) { return 0; } public static short bh_sr_short(short v) { return 0; } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c1/Test8275337.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c1/Test8275337.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c1/Test8275337.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c1/Test8275337.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8275337 + * @run main/othervm -Xcomp -XX:TieredStopAtLevel=1 compiler.c1.Test8275337 + */ + + +package compiler.c1; + +public class Test8275337 { + public static final int N = 400; + + public static void mainTest() { + int iArr1[] = new int[N]; + float fArr1[][] = new float[N][N]; + + for (int i = 9; i < 171; i++) { + int z; + try { + z = i % i; + } catch (ArithmeticException a_e) {} + for (int j = 1; j < 155; ++j) { + fArr1[j - 1][i] -= 1; + iArr1[i - 1] = 1; + } + for (int j = 4; j < 155; j++) { + for (int k = 1; k < 2; ++k) { + iArr1[i - 1] += 1; + fArr1[k - 1][j] -= 2; + } + } + } + } + public static void main(String[] strArr) { + + try { + for (int i = 0; i < 10; i++) { + mainTest(); + } + } catch (Exception ex) { + } + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java 2022-07-14 08:05:38.000000000 +0000 @@ -50,6 +50,7 @@ "-XX:TieredStopAtLevel=1", "-XX:+TraceRangeCheckElimination", "-XX:-BackgroundCompilation", + "-XX:CompileThreshold=500", test_constant_array.class.getName() }; @@ -69,6 +70,7 @@ "-XX:TieredStopAtLevel=1", "-XX:+TraceRangeCheckElimination", "-XX:-BackgroundCompilation", + "-XX:CompileThreshold=500", test_multi_constant_array.class.getName() }; @@ -88,6 +90,7 @@ "-XX:TieredStopAtLevel=1", "-XX:+TraceRangeCheckElimination", "-XX:-BackgroundCompilation", + "-XX:CompileThreshold=500", test_multi_new_array.class.getName() }; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeHotInlineTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeHotInlineTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeHotInlineTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeHotInlineTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8285394 + * @requires vm.compiler2.enabled + * @summary Blackholes should work when hot inlined + * @library /test/lib / + * @run driver compiler.c2.irTests.blackhole.BlackholeHotInlineTest + */ + +package compiler.c2.irTests.blackhole; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +public class BlackholeHotInlineTest { + + public static void main(String[] args) { + TestFramework.runWithFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:CompileCommand=blackhole,compiler.c2.irTests.blackhole.BlackholeHotInlineTest::blackhole", + "-XX:CompileCommand=dontinline,compiler.c2.irTests.blackhole.BlackholeHotInlineTest::dontinline" + ); + } + + static long x, y; + + /* + * Negative test: check that dangling expression is eliminated + */ + + @Test + @IR(failOn = IRNode.MUL_L) + static void testNothing() { + long r = x * y; + } + + @Run(test = "testNothing") + static void runNothing() { + testNothing(); + } + + /* + * Auxiliary test: check that dontinline method does not allow the elimination. + */ + + @Test + @IR(counts = {IRNode.MUL_L, "1"}) + static void testDontline() { + long r = x * y; + dontinline(r); + } + + static void dontinline(long x) {} + + @Run(test = "testDontline") + static void runDontinline() { + testDontline(); + } + + /* + * Positive test: check that blackhole method does not allow the elimination either. + */ + + @Test + @IR(counts = {IRNode.MUL_L, "1"}) + static void testBlackholed() { + long r = x * y; + blackhole(r); + } + + static void blackhole(long x) {} + + @Run(test = "testBlackholed") + static void runBlackholed() { + testBlackholed(); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeStoreStoreEATest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeStoreStoreEATest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeStoreStoreEATest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeStoreStoreEATest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8284848 + * @requires vm.compiler2.enabled + * @summary Blackhole arguments are globally escaping, thus preventing advanced EA optimizations + * @library /test/lib / + * @run driver compiler.c2.irTests.blackhole.BlackholeStoreStoreEATest + */ + +package compiler.c2.irTests.blackhole; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +public class BlackholeStoreStoreEATest { + + public static void main(String[] args) { + TestFramework.runWithFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileCommand=blackhole,compiler.c2.irTests.blackhole.BlackholeStoreStoreEATest::blackhole" + ); + } + + /* + * Negative test is not possible: the StoreStore barrier is still in, even if we just do dontinline. + * Positive test: check that blackhole keeps the StoreStore barrier in. + */ + + @Test + @IR(counts = {IRNode.MEMBAR_STORESTORE, "1"}) + static void testBlackholed() { + Object o = new Object(); + blackhole(o); + } + + static void blackhole(Object o) {} + + @Run(test = "testBlackholed") + static void runBlackholed() { + testBlackholed(); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeSyncEATest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeSyncEATest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeSyncEATest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/blackhole/BlackholeSyncEATest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8284848 + * @requires vm.compiler2.enabled + * @summary Blackhole arguments are globally escaping, thus preventing advanced EA optimizations + * @library /test/lib / + * @run driver compiler.c2.irTests.blackhole.BlackholeSyncEATest + */ + +package compiler.c2.irTests.blackhole; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +public class BlackholeSyncEATest { + + public static void main(String[] args) { + TestFramework.runWithFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileCommand=blackhole,compiler.c2.irTests.blackhole.BlackholeSyncEATest::blackhole", + "-XX:CompileCommand=dontinline,compiler.c2.irTests.blackhole.BlackholeSyncEATest::dontinline" + ); + } + + /* + * Negative test: check that dontinline method still allows EA to eliminate the synchronization. + */ + + @Test + @IR(failOn = {IRNode.FAST_LOCK, IRNode.FAST_UNLOCK}) + static void testDontline() { + Object o = new Object(); + synchronized (o) {} + dontinline(o); + } + + static void dontinline(Object o) {} + + @Run(test = "testDontline") + static void runDontinline() { + testDontline(); + } + + /* + * Positive test: check that blackhole keeps the synchronization in. + */ + + @Test + @IR(counts = {IRNode.FAST_LOCK, "1"}) + @IR(counts = {IRNode.FAST_UNLOCK, "1"}) + static void testBlackholed() { + Object o = new Object(); + synchronized (o) {} + blackhole(o); + } + + static void blackhole(Object o) {} + + @Run(test = "testBlackholed") + static void runBlackholed() { + testBlackholed(); + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8278228 + * @summary C2: Improve identical back-to-back if elimination + * @library /test/lib / + * @run driver compiler.c2.irTests.TestSkeletonPredicates + */ + +public class TestSkeletonPredicates { + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:-UseLoopPredicate", "-XX:LoopUnrollLimit=240", "-XX:+StressIGVN", "-XX:StressSeed=255527877"); + TestFramework.runWithFlags("-XX:-UseLoopPredicate", "-XX:LoopUnrollLimit=240", "-XX:+StressIGVN"); + } + + static volatile int barrier; + + @ForceInline + static boolean test1_helper(int start, int stop, double[] array1, double[] array2) { + for (int i = start; i < stop; i++) { + if ((i % 2) == 0) { + array1[i] = 42.42; + } else { + barrier = 0x42; + } + } + return false; + } + + @Test + @IR(counts = { IRNode.COUNTEDLOOP, "3" }) + static double[] test1(int stop, double[] array2) { + double[] array1 = null; + array1 = new double[10]; + for (int j = 0; j < stop; j++) { + if (test1_helper(8, j, array1, array2)) { + return null; + } + } + return array1; + } + + @Run(test = "test1") + void test1_runner() { + double[] array2 = new double[10]; + double[] array3 = new double[1000]; + test1_helper(1, 1000, array3, array3); + test1(11, array3); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/TestStripMiningDropsSafepoint.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/TestStripMiningDropsSafepoint.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/TestStripMiningDropsSafepoint.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/TestStripMiningDropsSafepoint.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8282045 + * @summary When loop strip mining fails, safepoints are removed from loop anyway + * @library /test/lib / + * @run driver compiler.c2.irTests.TestStripMiningDropsSafepoint + */ + +public class TestStripMiningDropsSafepoint { + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", "-XX:LoopMaxUnroll=1", "-XX:-RangeCheckElimination"); + TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", "-XX:LoopMaxUnroll=1", "-XX:-RangeCheckElimination", "-XX:-PartialPeelLoop"); + } + + @Test + @IR(applyIf = { "PartialPeelLoop", "true" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.OUTERSTRIPMINEDLOOP, "1", IRNode.SAFEPOINT, "1" }) + private static void test1(int[] dst, int[] src) { + // Partial peel is applied. No side effect between exit and + // safepoint. + for (int i = 0; ; ) { + // prevent ciTypeFlow from cloning head + synchronized (new Object()) {} + i++; + if (i >= src.length) { + break; + } + dst[i] = src[i]; + if (i / 2 >= 2000) { + break; + } + } + } + + @Run(test = "test1") + private static void test1_runner() { + int[] array1 = new int[1000]; + int[] array2 = new int[10000]; + test1(array1, array1); + test1(array2, array2); + } + + @Test + @IR(applyIf = { "PartialPeelLoop", "true" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.SAFEPOINT, "1" }) + @IR(applyIf = { "PartialPeelLoop", "true" }, failOn = { IRNode.OUTERSTRIPMINEDLOOP }) + private static void test2(int[] dst, int[] src) { + // Partial peel is applied. Some side effect between exit and + // safepoint. + int v = src[0]; + for (int i = 0; ; ) { + synchronized (new Object()) {} + dst[i] = v; + i++; + if (i >= src.length) { + break; + } + v = src[i]; + if (i / 2 >= 2000) { + break; + } + } + } + + @Run(test = "test2") + private static void test2_runner() { + int[] array1 = new int[1000]; + int[] array2 = new int[10000]; + test2(array1, array1); + test2(array2, array2); + } + + @Test + @IR(applyIf = { "PartialPeelLoop", "false" }, counts = { IRNode.COUNTEDLOOP, "1", IRNode.OUTERSTRIPMINEDLOOP, "1", IRNode.SAFEPOINT, "1" }) + private static void test3(int[] dst, int[] src) { + int v = src[0]; + for (int i = 0; ; ) { + synchronized (new Object()) {} + dst[i] = v; + int inc = test3_helper(2); + v = src[i]; + i += (inc / 2); + if (i >= src.length) { + break; + } + for (int j = 0; j < 10; j++) { + } + // safepoint on backedge + } + } + + private static int test3_helper(int stop) { + int i = 1; + do { + synchronized (new Object()) {} + i *= 2; + } while (i < stop); + return i; + } + + @Run(test = "test3") + private static void test3_runner() { + int[] array1 = new int[1000]; + test3(array1, array1); + test3_helper(10); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/TestSuperwordFailsUnrolling.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/TestSuperwordFailsUnrolling.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/irTests/TestSuperwordFailsUnrolling.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/irTests/TestSuperwordFailsUnrolling.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import sun.hotspot.WhiteBox; + +/* + * @test + * @bug 8283187 + * @summary C2: loop candidate for superword not always unrolled fully if superword fails + * @library /test/lib / + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -DSkipWhiteBoxInstall=true -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.c2.irTests.TestSuperwordFailsUnrolling + */ + +public class TestSuperwordFailsUnrolling { + private static int v = 0; + private final static WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + Object avx = wb.getVMFlag("UseAVX"); + if (avx != null && ((Long)avx) > 2) { + TestFramework.runWithFlags("-XX:UseAVX=2", "-XX:LoopMaxUnroll=8"); + } + TestFramework.runWithFlags("-XX:LoopMaxUnroll=8"); + } + + @Test + @IR(applyIf = { "UsePopCountInstruction", "true" }, counts = { IRNode.POPCOUNT_L, "10" }) + private static int test(long[] array1, long[] array2) { + v = 0; + for (int i = 0; i < array1.length; i++) { + v += Long.bitCount(array1[i]); + } + return v; + } + + @Run(test = "test") + void test_runner() { + long[] array = new long[1000]; + test(array, array); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestCMoveInfiniteGVN.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestCMoveInfiniteGVN.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestCMoveInfiniteGVN.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestCMoveInfiniteGVN.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 + * @key stress randomness + * @bug 8280123 + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.c2.TestCMoveInfiniteGVN::test + * -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:StressSeed=43739875 + * compiler.c2.TestCMoveInfiniteGVN + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.c2.TestCMoveInfiniteGVN::test + * -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN + * compiler.c2.TestCMoveInfiniteGVN + */ + +package compiler.c2; + +public class TestCMoveInfiniteGVN { + + static int test(boolean b, int i) { + int iArr[] = new int[2]; + + double d = Math.max(i, i); + for (int i1 = 1; i1 < 2; i1++) { + if (i1 != 0) { + return (b ? 1 : 0); // CMoveI + } + for (int i2 = 1; i2 < 2; i2++) { + switch (i2) { + case 1: d -= Math.max(i1, i2); break; + } + d -= iArr[i1 - 1]; + } + } + return 0; + } + + static void test() { + test(true, 234); + } + + public static void main(String[] strArr) { + test(); // compilation, then nmethod invalidation during execution + test(); // trigger crashing recompilation + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestJumpTable.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestJumpTable.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestJumpTable.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestJumpTable.java 2022-07-14 08:05:38.000000000 +0000 @@ -25,6 +25,8 @@ * @test * @bug 8229855 8238812 * @summary Test jump table with key value that gets out of bounds after loop unrolling. + * @requires vm.compiler2.enabled + * * @run main/othervm -XX:CompileCommand=dontinline,compiler.c2.TestJumpTable::test* * -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:-UseSwitchProfiling * compiler.c2.TestJumpTable diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8283451 + * @summary C2: assert(_base == Long) failed: Not a Long + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM -XX:+StressGCM -XX:+StressCCP -XX:+StressIGVN + * -Xcomp -XX:CompileOnly=TestModDivTopInput -XX:-TieredCompilation -XX:StressSeed=87628618 TestModDivTopInput + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM -XX:+StressGCM -XX:+StressCCP -XX:+StressIGVN + * -Xcomp -XX:CompileOnly=TestModDivTopInput -XX:-TieredCompilation TestModDivTopInput + */ + +public class TestModDivTopInput { + + public static final int N = 400; + + public static float fFld=-2.447F; + public long lFld=-189L; + + public void mainTest(String[] strArr1) { + + int i18, i20=-14, i21, iArr2[]=new int[N]; + boolean b2=true; + double d2; + long l; + + init(iArr2, -13265); + + for (i18 = 13; i18 < 315; ++i18) { + if (b2) continue; + for (d2 = 5; d2 < 83; d2++) { + } + for (i21 = 4; i21 < 83; i21++) { + for (l = 1; 2 > l; l++) { + } + b2 = b2; + lFld %= (i20 | 1); + i20 = (int)fFld; + i20 += (int)d2; + } + } + } + + public static void main(String[] strArr) { + TestModDivTopInput _instance = new TestModDivTopInput(); + for (int i = 0; i < 10; i++ ) { + _instance.mainTest(strArr); + } + } + + static void init(int[] arr, int v) { + for (int i = 0; i < arr.length; i++) { + arr[i] = v; + } + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestReplaceEquivPhis.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestReplaceEquivPhis.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestReplaceEquivPhis.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestReplaceEquivPhis.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. * 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 8243670 * @summary Unexpected test result caused by C2 MergeMemNode::Ideal + * @requires vm.compiler2.enabled * * @run main/othervm -Xcomp -XX:-SplitIfBlocks * -XX:CompileOnly=compiler.c2.TestReplaceEquivPhis::test diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestShiftRightAndAccumulate.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestShiftRightAndAccumulate.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/c2/TestShiftRightAndAccumulate.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/c2/TestShiftRightAndAccumulate.java 2022-07-14 08:05:38.000000000 +0000 @@ -25,8 +25,17 @@ * @test * @bug 8260585 * @summary AArch64: Wrong code generated for shifting right and accumulating four unsigned short integers. + * * @run main/othervm compiler.c2.TestShiftRightAndAccumulate * @run main/othervm -Xcomp compiler.c2.TestShiftRightAndAccumulate + */ + +/** + * @test + * @bug 8260585 + * @summary AArch64: Wrong code generated for shifting right and accumulating four unsigned short integers. + * @requires vm.compiler2.enabled + * * @run main/othervm -XX:-SuperWordLoopUnrollAnalysis compiler.c2.TestShiftRightAndAccumulate */ diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,12 +50,23 @@ */ package compiler.cha; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + import static compiler.cha.Utils.*; public class AbstractRootMethod { public static void main(String[] args) { run(AbstractClass.class); run(AbstractInterface.class); + + // Implementation limitation: CHA is not performed by C1 during inlining through MH linkers. + if (!sun.hotspot.code.Compiler.isC1Enabled()) { + run(AbstractClass.TestMH.class, AbstractClass.class); + run(AbstractInterface.TestMH.class, AbstractInterface.class); + } + + System.out.println("TEST PASSED"); } public static class AbstractClass extends ATest { @@ -124,7 +135,21 @@ call(new G() { public Object m() { return CORRECT; } }); // Gn <: G.m <: C.m ABSTRACT assertCompiled(); } + + public static class TestMH extends AbstractClass { + static final MethodHandle TEST_MH = findVirtualHelper(C.class, "m", Object.class, MethodHandles.lookup()); + + @Override + public Object test(C obj) { + try { + return TEST_MH.invokeExact(obj); // invokevirtual C.m() + } catch (Throwable e) { + throw new InternalError(e); + } + } + } } + public static class AbstractInterface extends ATest { public AbstractInterface() { super(C.class, D.class); @@ -193,5 +218,18 @@ call(new G() { public Object m() { return CORRECT; } }); // Gn <: G.m <: C <: I.m ABSTRACT assertCompiled(); } + + public static class TestMH extends AbstractInterface { + static final MethodHandle TEST_MH = findVirtualHelper(C.class, "m", Object.class, MethodHandles.lookup()); + + @Override + public Object test(C obj) { + try { + return TEST_MH.invokeExact(obj); // invokevirtual C.m() + } catch (Throwable e) { + throw new InternalError(e); + } + } + } } } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,12 +50,22 @@ */ package compiler.cha; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + import static compiler.cha.Utils.*; public class DefaultRootMethod { public static void main(String[] args) { run(DefaultRoot.class); run(InheritedDefault.class); + + // Implementation limitation: CHA is not performed by C1 during inlining through MH linkers. + if (!sun.hotspot.code.Compiler.isC1Enabled()) { + run(DefaultRoot.TestMH.class, DefaultRoot.class); + run(InheritedDefault.TestMH.class, InheritedDefault.class); + } + System.out.println("TEST PASSED"); } @@ -83,7 +93,7 @@ static class G extends C { public Object m() { return CORRECT; } } @Override - public Object test(C obj) { + public Object test(C obj) throws Throwable { return obj.m(); // invokevirtual C.m() } @@ -122,6 +132,15 @@ call(new G() { public Object m() { return CORRECT; } }); // Gn <: G.m <: C <: I.m DEFAULT assertCompiled(); } + + public static class TestMH extends DefaultRoot { + static final MethodHandle TEST_MH = findVirtualHelper(C.class, "m", Object.class, MethodHandles.lookup()); + + @Override + public Object test(C obj) throws Throwable { + return TEST_MH.invokeExact(obj); // invokevirtual C.m() + } + } } public static class InheritedDefault extends ATest { @@ -151,7 +170,7 @@ static class G extends C implements K { /* inherits K.m DEFAULT */ } @Override - public Object test(C obj) { + public Object test(C obj) throws Throwable { return obj.m(); // invokevirtual C.m() } @@ -190,5 +209,14 @@ call(new G() { public Object m() { return CORRECT; } }); // Gn <: G.m <: C <: I.m DEFAULT assertCompiled(); } + + public static class TestMH extends InheritedDefault { + static final MethodHandle TEST_MH = findVirtualHelper(C.class, "m", Object.class, MethodHandles.lookup()); + + @Override + public Object test(C obj) throws Throwable { + return TEST_MH.invokeExact(obj); // invokevirtual C.m() + } + } } } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/cha/Utils.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/cha/Utils.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/cha/Utils.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/cha/Utils.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Method; import java.util.HashMap; import java.util.concurrent.Callable; @@ -45,6 +46,7 @@ public class Utils { public static final Unsafe U = Unsafe.getUnsafe(); + public static final WhiteBox WB = WhiteBox.getWhiteBox(); interface Test { void call(T o); @@ -99,8 +101,6 @@ } public static abstract class ATest implements Test { - public static final WhiteBox WB = WhiteBox.getWhiteBox(); - public static final Object CORRECT = new Object(); public static final Object WRONG = new Object(); @@ -117,7 +117,7 @@ } @DontInline - public abstract Object test(T i); + public abstract Object test(T i) throws Throwable; public abstract void checkInvalidReceiver(); @@ -133,7 +133,6 @@ })); } - public void compile(Runnable r) { while (!WB.isMethodCompiled(TEST)) { for (int i = 0; i < 100; i++) { @@ -161,19 +160,35 @@ @Override public void call(T i) { - assertTrue(test(i) != WRONG); + try { + assertTrue(test(i) != WRONG); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + public static T compute(Callable c) { + try { + return c.call(); + } catch (Exception e) { + throw new Error(e); + } + } + + public static MethodHandle findVirtualHelper(Class refc, String name, Class returnType, MethodHandles.Lookup lookup) { + return compute(() -> lookup.findVirtual(refc, name, MethodType.methodType(returnType))); } } @Retention(value = RetentionPolicy.RUNTIME) public @interface TestCase {} - static void run(Class test) { + static void run(Class test, Class enclosed) { try { - for (Method m : test.getDeclaredMethods()) { + for (Method m : test.getMethods()) { if (m.isAnnotationPresent(TestCase.class)) { System.out.println(m.toString()); - ClassLoader cl = new MyClassLoader(test); + ClassLoader cl = new MyClassLoader(enclosed); Class c = cl.loadClass(test.getName()); c.getMethod(m.getName()).invoke(c.getDeclaredConstructor().newInstance()); } @@ -183,6 +198,10 @@ } } + static void run(Class test) { + run(test, test); + } + static class ObjectToStringHelper { static Object testHelper(Object o) { throw new Error("not used"); @@ -303,7 +322,7 @@ try { r.run(); throw new AssertionError("Exception not thrown: " + expectedException.getName()); - } catch(Throwable e) { + } catch (Throwable e) { if (expectedException == e.getClass()) { // success: proper exception is thrown } else { @@ -320,12 +339,4 @@ throw new Error(e); } } - - static T compute(Callable c) { - try { - return c.call(); - } catch (Exception e) { - throw new Error(e); - } - } } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. * 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 OverflowCodeCacheTest - * @bug 8059550 + * @bug 8059550 8279356 * @summary testing of code cache segments overflow * @library /test/lib * @modules java.base/jdk.internal.misc @@ -33,11 +33,14 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* - * -XX:-SegmentedCodeCache - * compiler.codecache.OverflowCodeCacheTest + * -XX:-SegmentedCodeCache -Xmixed + * compiler.codecache.OverflowCodeCacheTest CompilationDisabled * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* - * -XX:+SegmentedCodeCache + * -XX:+SegmentedCodeCache -Xmixed + * compiler.codecache.OverflowCodeCacheTest CompilationDisabled + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache -Xmixed * compiler.codecache.OverflowCodeCacheTest */ @@ -49,13 +52,21 @@ import sun.hotspot.code.CodeBlob; import java.lang.management.MemoryPoolMXBean; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.EnumSet; +class Helper { + // Uncommon signature to prevent sharing and force creation of a new adapter + public void method(float a, float b, float c, Object o) { } +} + public class OverflowCodeCacheTest { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static boolean COMPILATION_DISABLED = false; public static void main(String[] args) { + COMPILATION_DISABLED = args.length > 0; EnumSet blobTypes = BlobType.getAvailable(); for (BlobType type : blobTypes) { new OverflowCodeCacheTest(type).test(); @@ -74,6 +85,8 @@ System.out.println("allocating till possible..."); ArrayList blobs = new ArrayList<>(); int compilationActivityMode = -1; + // Lock compilation to be able to better control code cache space + WHITE_BOX.lockCompilation(); try { long addr; int size = (int) (getHeapSize() >> 7); @@ -88,15 +101,43 @@ } } /* now, remember compilationActivityMode to check it later, after freeing, since we - possibly have no free cache for futher work */ + possibly have no free cache for further work */ compilationActivityMode = WHITE_BOX.getCompilationActivityMode(); + + // Use smallest allocation size to make sure all of the available space + // is filled up. Don't free these below to put some pressure on the sweeper. + while ((addr = WHITE_BOX.allocateCodeBlob(1, type.id)) != 0) { } } finally { + try { + // Trigger creation of a new adapter for Helper::method + // which will fail because we are out of code cache space. + Helper helper = new Helper(); + } catch (VirtualMachineError e) { + // Expected + } + // Free code cache space for (Long blob : blobs) { WHITE_BOX.freeCodeBlob(blob); } + + // Convert some nmethods to zombie and then free them to re-enable compilation + WHITE_BOX.unlockCompilation(); + WHITE_BOX.forceNMethodSweep(); + WHITE_BOX.forceNMethodSweep(); + + // Trigger compilation of Helper::method which will hit an assert because + // adapter creation failed above due to a lack of code cache space. + Helper helper = new Helper(); + for (int i = 0; i < 100_000; i++) { + helper.method(0, 0, 0, null); + } + } + // Only check this if compilation is disabled, otherwise the sweeper might have + // freed enough nmethods to allow for re-enabling compilation. + if (COMPILATION_DISABLED) { + Asserts.assertNotEquals(compilationActivityMode, 1 /* run_compilation*/, + "Compilation must be disabled when CodeCache(CodeHeap) overflows"); } - Asserts.assertNotEquals(compilationActivityMode, 1 /* run_compilation*/, - "Compilation must be disabled when CodeCache(CodeHeap) overflows"); } private long getHeapSize() { diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ * -XX:+SegmentedCodeCache * -XX:ReservedCodeCacheSize=16M * -XX:CodeCacheMinBlockLength=1 + * -XX:CICompilerCount=2 * compiler.codecache.stress.ReturnBlobToWrongHeapTest */ diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/codegen/ClearArrayTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/codegen/ClearArrayTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/codegen/ClearArrayTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/codegen/ClearArrayTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -25,7 +25,10 @@ * @test * @bug 8260716 * @summary Test for correct code generation by the JIT - * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,*ClearArrayTest.test -XX:+UnlockDiagnosticVMOptions -XX:-IdealizeClearArrayNode compiler.codegen.ClearArrayTest + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,*ClearArrayTest.test + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:-IdealizeClearArrayNode + * compiler.codegen.ClearArrayTest */ package compiler.codegen; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/compilercontrol/CompilationModeHighOnlyTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/compilercontrol/CompilationModeHighOnlyTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/compilercontrol/CompilationModeHighOnlyTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/compilercontrol/CompilationModeHighOnlyTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -24,6 +24,7 @@ /* * @test * @bug 8233885 + * @requires (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @summary CompLevel_initial_compile should be CompLevel_full_optimization for high-only mode * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:CompilationMode=high-only * -XX:CompileCommand=compileonly,java.lang.Object:: diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/exceptions/TestLateMHInlineExceptions.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/exceptions/TestLateMHInlineExceptions.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/exceptions/TestLateMHInlineExceptions.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/exceptions/TestLateMHInlineExceptions.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8275638 8278966 + * @summary GraphKit::combine_exception_states fails with "matching stack sizes" assert + * + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestLateMHInlineExceptions::m + * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline TestLateMHInlineExceptions + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacements -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline + * TestLateMHInlineExceptions + * + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class TestLateMHInlineExceptions { + public static void main(String[] args) throws Throwable { + TestLateMHInlineExceptions test = new TestLateMHInlineExceptions(); + for (int i = 0; i < 20_000; i++) { + test1(test); + try { + test1(null); + } catch (NullPointerException npe) { + } + test2(test); + test2(null); + test3(test); + try { + test3(null); + } catch (NullPointerException npe) { + } + test4(test); + test4(null); + test5(test); + try { + test5(null); + } catch (NullPointerException npe) { + } + test6(test); + try { + test6(null); + } catch (NullPointerException npe) { + } + } + } + + void m() { + } + + static void nothing(Throwable t) { + } + + static final MethodHandle mh; + static final MethodHandle mh_nothing; + static final MethodHandle mh2; + static final MethodHandle mh3; + + static { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + mh = lookup.findVirtual(TestLateMHInlineExceptions.class, "m", MethodType.methodType(void.class)); + mh_nothing = lookup.findStatic(TestLateMHInlineExceptions.class, "nothing", MethodType.methodType(void.class, Throwable.class)); + mh2 = MethodHandles.tryFinally(mh, mh_nothing); + mh3 = MethodHandles.catchException(mh, Throwable.class, mh_nothing); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + throw new RuntimeException("Method handle lookup failed"); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException("Method handle lookup failed"); + } + } + + private static void test1(TestLateMHInlineExceptions test) throws Throwable { + mh.invokeExact(test); + } + + private static void test2(TestLateMHInlineExceptions test) throws Throwable { + try { + mh.invokeExact(test); + } catch (NullPointerException npe) { + } + } + + private static void inlined(TestLateMHInlineExceptions test) throws Throwable { + mh.invokeExact(test); + } + + + private static void test3(TestLateMHInlineExceptions test) throws Throwable { + inlined(test); + } + + private static void test4(TestLateMHInlineExceptions test) throws Throwable { + try { + inlined(test); + } catch (NullPointerException npe) { + } + } + + private static void test5(TestLateMHInlineExceptions test) throws Throwable { + mh2.invokeExact(test); + } + + private static void test6(TestLateMHInlineExceptions test) throws Throwable { + mh3.invokeExact(test); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8279515 + * + * @requires vm.flagless & vm.compiler1.enabled & vm.compiler2.enabled + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * + * @run driver compiler.jsr292.ResolvedClassTest + */ + +package compiler.jsr292; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.IOException; + +public class ResolvedClassTest { + /* ======================================================================== */ + static void testStatic() throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestStatic.class.getName() + "::test", + TestStatic.class.getName()); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("TestStatic$A::m (1 bytes) not inlineable"); + analyzer.shouldNotContain("TestStatic$A::m (1 bytes) no static binding"); + + analyzer.shouldContain("TestStatic$A::m (1 bytes) inline"); + } + + static class TestStatic { + static class A { + static void m() {} + } + static class B extends A {} + + // @DontInline + static void test() { + B.m(); // invokestatic B "m" => A::m + } + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(); + } + } + } + + /* ======================================================================== */ + static void testStaticInit() throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestStaticInit.class.getName() + "::test", + TestStaticInit.class.getName()); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldContain("TestStaticInit$A::m (1 bytes) no static binding"); + } + + static class TestStaticInit { + static class A { + static { + for (int i = 0; i < 20_000; i++) { + TestStaticInit.test(); + } + } + + static void m() {} + } + static class B extends A {} + + // @DontInline + static void test() { + B.m(); // A:: => test() => A::m() + } + + public static void main(String[] args) { + A.m(); // trigger initialization of A + } + } + + /* ======================================================================== */ + static void testIndy() throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestIndy.class.getName() + "::test", + TestIndy.class.getName()); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotMatch("java\\.lang\\.invoke\\..+::linkToTargetMethod \\(9 bytes\\) not inlineable"); + + analyzer.shouldMatch("java\\.lang\\.invoke\\..+::linkToTargetMethod \\(9 bytes\\) force inline by annotation"); + analyzer.shouldContain("java/lang/invoke/MethodHandle::invokeBasic (not loaded) not inlineable"); + } + + static class TestIndy { + static String str = ""; + + // @DontInline + static void test() { + String s1 = "" + str; // indy (linked) + + for (int i = 0; i < 200_000; i++) {} // trigger OSR compilation + + String s2 = "" + str; // indy (not linked) + } + + public static void main(String[] args) { + test(); + } + } + + /* ======================================================================== */ + + public static void main(String[] args) throws IOException { + testStatic(); + testStaticInit(); + testIndy(); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/interpreter/Custom.jasm openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/interpreter/Custom.jasm --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/interpreter/Custom.jasm 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/interpreter/Custom.jasm 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler/interpreter; + +/* JASM simplified from the following Java pattern: + * + * public class Custom { + * + * static void test(int v) { + * int i8 = 1; + * try { + * v += 1; + * } catch (ArithmeticException exc1) { + * } finally { + * for (; i8 < 100; i8++) { + * } + * } + * } + * + */ + +super public class Custom { + + public static Method test:"(I)V" stack 2 locals 3 { + iconst_1; + istore_1; + try t0; + iinc 0, 1; + endtry t0; +Loop: + iload_1; + bipush 100; + if_icmpge Lexit; + iinc 1, 1; + goto Loop; // deoptimize here on backwards branch + catch t0 java/lang/ArithmeticException; // unreachable block + astore_2; +Lexit: + return + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/interpreter/VerifyStackWithUnreachableBlock.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/interpreter/VerifyStackWithUnreachableBlock.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/interpreter/VerifyStackWithUnreachableBlock.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/interpreter/VerifyStackWithUnreachableBlock.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 VerifyStackWithUnreachableBlock + * @bug 8271055 + * @compile Custom.jasm VerifyStackWithUnreachableBlock.java + * @summary Using VerifyStack for method that contains unreachable basic blocks + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack compiler.interpreter.VerifyStackWithUnreachableBlock + */ + +package compiler.interpreter; + +public class VerifyStackWithUnreachableBlock { + public static void main(String[] strArr) { + for (int i = 0; i < 10000; i++) { + Custom.test(i); + } + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics2.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics2.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics2.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics2.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -706,4 +706,18 @@ } } + static String longLatin1 = "0123456789A".repeat(100); + static String longUTF = "0123456789\ubeef".repeat(100); + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "0123456789", "1" }) + public static boolean indexOf_use_result_immediately(String a, String b) { + char ch = b.charAt(0); + return ch == a.charAt(a.indexOf(ch)); + } + + @Test(role = Role.TEST_ENTRY) + public static void test_indexOf_use_result_immediately() { + assertTrue(indexOf_use_result_immediately(longLatin1, "A")); + assertTrue(indexOf_use_result_immediately(longUTF, "\ubeef")); + } } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/jsr292/cr8026328/libTest8026328.c openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/jsr292/cr8026328/libTest8026328.c --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/jsr292/cr8026328/libTest8026328.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/jsr292/cr8026328/libTest8026328.c 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ void* reserved) { jvmtiCapabilities capa; - jvmtiEventCallbacks cbs = {0}; + jvmtiEventCallbacks cbs; (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0); @@ -110,6 +110,7 @@ capa.can_generate_single_step_events = 1; (*jvmti)->AddCapabilities(jvmti, &capa); + memset(&cbs, 0, sizeof(cbs)); cbs.ClassPrepare = classprepare; cbs.Breakpoint = breakpoint; (*jvmti)->SetEventCallbacks(jvmti, &cbs, sizeof(cbs)); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestTranslatedException.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestTranslatedException.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestTranslatedException.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestTranslatedException.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ /* * @test * @requires vm.jvmci - * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:open + * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:+open + * java.base/jdk.internal.misc * @library /compiler/jvmci/jdk.vm.ci.hotspot.test/src * @run testng/othervm * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler @@ -41,6 +42,9 @@ import org.testng.Assert; import org.testng.annotations.Test; +import jdk.internal.misc.Unsafe; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; + public class TestTranslatedException { @SuppressWarnings("serial") public static class Untranslatable extends RuntimeException { @@ -56,7 +60,7 @@ Class translatedExceptionClass = Class.forName("jdk.vm.ci.hotspot.TranslatedException"); Method encode = translatedExceptionClass.getDeclaredMethod("encodeThrowable", Throwable.class); - Method decode = translatedExceptionClass.getDeclaredMethod("decodeThrowable", String.class); + Method decode = translatedExceptionClass.getDeclaredMethod("decodeThrowable", byte[].class); encode.setAccessible(true); decode.setAccessible(true); @@ -64,11 +68,50 @@ for (int i = 0; i < 10; i++) { throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke")); } - String encoding = (String) encode.invoke(null, throwable); + byte[] encoding = (byte[]) encode.invoke(null, throwable); Throwable decoded = (Throwable) decode.invoke(null, encoding); assertThrowableEquals(throwable, decoded); } + @SuppressWarnings("unchecked") + @Test + public void encodeDecodeTest2() throws Exception { + Unsafe unsafe = Unsafe.getUnsafe(); + int bufferSize = 512; + long buffer = 0L; + while (true) { + buffer = unsafe.allocateMemory(bufferSize); + try { + Throwable throwable = new ExceptionInInitializerError(new InvocationTargetException(new Untranslatable("test exception", new NullPointerException()), "invoke")); + for (int i = 0; i < 10; i++) { + throwable = new ExceptionInInitializerError(new InvocationTargetException(new RuntimeException(String.valueOf(i), throwable), "invoke")); + } + + Method encode = HotSpotJVMCIRuntime.class.getDeclaredMethod("encodeThrowable", Throwable.class, long.class, int.class); + Method decode = HotSpotJVMCIRuntime.class.getDeclaredMethod("decodeAndThrowThrowable", long.class); + encode.setAccessible(true); + decode.setAccessible(true); + + int res = (Integer) encode.invoke(null, throwable, buffer, bufferSize); + + if (res < 0) { + bufferSize = -res; + } else { + try { + decode.invoke(null, buffer); + throw new AssertionError("expected decodeAndThrowThrowable to throw an exception"); + } catch (InvocationTargetException e) { + Throwable decoded = e.getCause(); + assertThrowableEquals(throwable, decoded); + } + return; + } + } finally { + unsafe.freeMemory(buffer); + } + } + } + private static void assertThrowableEquals(Throwable original, Throwable decoded) { try { Assert.assertEquals(original == null, decoded == null); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java 2022-07-14 08:05:38.000000000 +0000 @@ -42,6 +42,8 @@ import static java.lang.reflect.Modifier.isProtected; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; +import static jdk.vm.ci.meta.MetaUtil.internalNameToJava; +import static jdk.vm.ci.meta.MetaUtil.toInternalName; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -163,16 +165,15 @@ } @Test - public void internalNameTest() { - // Verify that the last slash in lambda types are not replaced with a '.' as they - // are part of the type name. + public void lambdaInternalNameTest() { + // Verify that the last dot in lambda types is properly handled when transitioning from internal name to java + // name and vice versa. Supplier lambda = () -> () -> System.out.println("run"); ResolvedJavaType lambdaType = metaAccess.lookupJavaType(lambda.getClass()); String typeName = lambdaType.getName(); - int typeNameLen = TestResolvedJavaType.class.getSimpleName().length(); - int index = typeName.indexOf(TestResolvedJavaType.class.getSimpleName()); - String suffix = typeName.substring(index + typeNameLen, typeName.length() - 1); - assertEquals(TestResolvedJavaType.class.getName() + suffix, lambdaType.toJavaName()); + String javaName = lambda.getClass().getName(); + assertEquals(typeName, toInternalName(javaName)); + assertEquals(javaName, internalNameToJava(typeName, true, true)); } @Test diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java 2022-07-14 08:05:38.000000000 +0000 @@ -113,6 +113,7 @@ public static final String LOOP = START + "Loop" + MID + END; public static final String COUNTEDLOOP = START + "CountedLoop\\b" + MID + END; public static final String COUNTEDLOOP_MAIN = START + "CountedLoop\\b" + MID + "main" + END; + public static final String OUTERSTRIPMINEDLOOP = START + "OuterStripMinedLoop\\b" + MID + END; public static final String CALL = START + "Call.*Java" + MID + END; public static final String CALL_OF_METHOD = COMPOSITE_PREFIX + START + "Call.*Java" + MID + IS_REPLACED + " " + END; @@ -132,6 +133,14 @@ public static final String SCOPE_OBJECT = "(.*# ScObj.*" + END; public static final String MEMBAR = START + "MemBar" + MID + END; + public static final String MEMBAR_STORESTORE = START + "MemBarStoreStore" + MID + END; + public static final String SAFEPOINT = START + "SafePoint" + MID + END; + + public static final String MUL_L = START + "MulL" + MID + END; + public static final String POPCOUNT_L = START + "PopCountL" + MID + END; + + public static final String FAST_LOCK = START + "FastLock" + MID + END; + public static final String FAST_UNLOCK = START + "FastUnlock" + MID + END; /** * Called by {@link IRMatcher} to merge special composite nodes together with additional user-defined input. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/longcountedloops/TestIVPhiTypeIncorrectAfterCCP.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/longcountedloops/TestIVPhiTypeIncorrectAfterCCP.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/longcountedloops/TestIVPhiTypeIncorrectAfterCCP.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/longcountedloops/TestIVPhiTypeIncorrectAfterCCP.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8277906 + * @summary Incorrect type for IV phi of long counted loops after CCP + * + * @run main/othervm -XX:-TieredCompilation -XX:CompileCommand=compileonly,TestIVPhiTypeIncorrectAfterCCP::test -XX:-BackgroundCompilation TestIVPhiTypeIncorrectAfterCCP + * + */ + +public class TestIVPhiTypeIncorrectAfterCCP { + + static int test() { + int array[] = new int[50]; + + float f = 0; + for (int i = 3; i < 49; i++) { + for (long l = 1; l < i; l++) { + array[(int)l] = i; + f += l; + } + } + int sum = 0; + for (int i = 0; i < array.length; i++) { + sum += array[i]; + } + return sum; + } + + public static void main(String[] args) { + long expected = test(); + for (int i = 0; i < 10_000; i++) { + int res = test(); + if (res != expected) { + throw new RuntimeException("Unexpected result: " + res + " != " + expected); + } + } + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 8283408 + * @summary Fill a byte array with Java Unsafe API + * @run main/othervm -XX:+OptimizeFill compiler.loopopts.FillArrayWithUnsafe + */ + +package compiler.loopopts; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +public class FillArrayWithUnsafe { + + private static Unsafe unsafe; + + public static void main(String[] args) throws Exception { + Class klass = Unsafe.class; + Field field = klass.getDeclaredField("theUnsafe"); + field.setAccessible(true); + unsafe = (Unsafe) field.get(null); + + byte[] buffer; + // Make sure method newByteArray is compiled by C2 + for (int i = 0; i < 50000; i++) { + buffer = newByteArray(100, (byte) 0x80); + } + } + + public static byte[] newByteArray(int size, byte val) { + byte[] arr = new byte[size]; + int offset = unsafe.arrayBaseOffset(byte[].class); + for (int i = offset; i < offset + size; i++) { + unsafe.putByte(arr, i, val); + } + return arr; + } +} + diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/TestCastIIMakesMainLoopPhiDead.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 8280600 + * @summary C2: assert(!had_error) failed: bad dominance + * @run main/othervm -Xcomp -XX:CompileOnly=TestCastIIMakesMainLoopPhiDead TestCastIIMakesMainLoopPhiDead + */ + +public class TestCastIIMakesMainLoopPhiDead { + int iArr[] = new int[0]; + + void test() { + int x = 8; + try { + for (int i = 0; i < 8; i++) { + iArr[1] = 9; + for (int j = -400; 1 > j; j++) { + iArr[j] = 4; + x -= 2; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + } + } + public static void main(String[] k) { + TestCastIIMakesMainLoopPhiDead t = new TestCastIIMakesMainLoopPhiDead(); + for (int i = 0; i < 3; i++) { + t.test(); + } + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithRegionHead.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithRegionHead.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithRegionHead.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithRegionHead.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @requires vm.compiler2.enabled + * @bug 8279837 + * @summary Tests infinite loop with region head in iteration split. + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.loopopts.TestIterationSplitWithRegionHead::test + * -XX:CompileCommand=dontinline,compiler.loopopts.TestIterationSplitWithRegionHead::* + * compiler.loopopts.TestIterationSplitWithRegionHead + */ + +package compiler.loopopts; + +public class TestIterationSplitWithRegionHead { + + static boolean flagFalse = false; + + public static void main(String[] args) { + test(); + } + + public static void test() { + // 1) The loop tree is built. We find that nested loop N2 is an infinite loop and add a NeverBranch + // to the inner loop to make it reachable. But the current loop tree does not have N2, yet. The + // resulting loop tree is: + // + // Loop: N0/N0 has_call has_sfpt + // Loop: N77/N121 has_call // N1 outer + // Loop: N77/N111 has_call sfpts={ 111 97 } // N1 inner + // + // 2) beautify_loops() finds that the outer loop head of N1 is shared and thus adds a new region + // in merge_many_backedges(). As a result, the loop tree is built again. This time, the NeverBranch + // in the inner loop of N2 allows that a loop tree can be built for it: + // + // Loop: N0/N0 has_call has_sfpt + // Loop: N216/N213 limit_check profile_predicated predicated has_call sfpts={ 111 97 } // N1 shared loop head + // Loop: N196/N201 sfpts={ 201 } // N2 inner loop now discovered with the new NeverBranch + // + // However, a LoopNode is only added by beautify_loops() which won't be called until the next iteration of loop opts. + // This means that we have a Region node (N196) as head in the loop tree which cannot be handled by iteration_split_impl() + // resulting in an assertion failure. + + // Nested loop N1 + while (flagFalse) { + while (dontInlineFalse()) { + } + } + dontInlineFalse(); + + // Nested loop N2 + while (flagFalse) { + while (true) ; // Detected as infinite inner loop by C2 -> NeverBranch added + } + } + + public static boolean dontInlineFalse() { + return false; + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * 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 8275854 + * @summary Crashes in PhaseIdealLoop::transform_long_counted_loop + * @requires vm.compiler2.enabled + * + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,TestLoopEndNodeEliminate::lMeth TestLoopEndNodeEliminate + * + */ + +public class TestLoopEndNodeEliminate { + public volatile boolean bFld=true; + public volatile byte byFld=0; + public volatile short sArrFld[]=new short[N]; + public int iArrFld[]=new int[N]; + public boolean bArrFld[]=new boolean[N]; + + public static int iFld=10; + public static final int N = 400; + public static long instanceCount=0L; + public static long lMeth_check_sum = 0; + + public long lMeth() { + long l1=-33582180L; + int i14=-5, i15=-14, i16=0, i17=25699, i18=97, i19=-3, i20=0, i21=0, i22=42, i23=0, i24=25699, i25=97; + + for (l1 = 286; l1 > 16; l1 -= 3) { + for (i15 = 17; i15 > l1; --i15) { + switch (((iArrFld[i15] >>> 1) % 7) + 101) { + case 101: + case 102: + case 103: + case 104: + for (i17 = (int)(l1); i17 < 1; i17++) { + bArrFld[i17] = bFld; + } + break; + case 105: + case 106: + case 107: + } + } + for (i19 = 1; i19 < 270; ++i19) { + TestLoopEndNodeEliminate.iFld += byFld; + i21 = 1; + while (++i21 < 2) { + bFld = true; + } + for (i22 = 1; 2 > i22; ++i22) { + bFld = true; + } + for (i24 = 1; 2 > i24; ++i24) { + bFld = true; + } + bArrFld[(int)(l1) % N] = bFld; + sArrFld[i19 - 1] ^= (short)(++TestLoopEndNodeEliminate.instanceCount); + } + } + long meth_res = l1 + i14 + i15 + i16 + i17 + i18 + i19 + i20 + i21 + i22 + i23 + i24 + i25; + lMeth_check_sum += meth_res; + return (long)meth_res; + } + + public static void main(String[] strArr) { + TestLoopEndNodeEliminate _instance = new TestLoopEndNodeEliminate(); + for (int i = 0; i < 10000; i++ ) { + _instance.lMeth(); + } + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/loopopts/TestPredicateInputBelowLoopPredicate.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 8280799 + * @summary C2: assert(false) failed: cyclic dependency prevents range check elimination + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseCountedLoopSafepoints TestPredicateInputBelowLoopPredicate + */ + +public class TestPredicateInputBelowLoopPredicate { + private static final Object object = new Object(); + private static int fieldStop = 100; + private static int[] array = new int[200]; + private static int[] array2 = new int[200]; + private static int fieldStart = 0; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(true); + test(false); + } + } + + private static void test(boolean flag) { + if (array == null) { + } + int start = fieldStart; + int i = start; + for(;;) { + int j; + for (j = -10; j < 0; j++) { + } + int stop = fieldStop; + // bound check becomes candidate for predication once + // loop above is optimized out + array[stop - i + j] = 0; + + // A bunch of stuff to grow loop body size and prevent peeling: + array2[0] = 0; + array2[1] = 0; + array2[2] = 0; + array2[3] = 0; + array2[4] = 0; + array2[5] = 0; + array2[6] = 0; + array2[7] = 0; + array2[8] = 0; + array2[9] = 0; + array2[10] = 0; + array2[11] = 0; + array2[12] = 0; + array2[13] = 0; + array2[14] = 0; + array2[15] = 0; + array2[16] = 0; + array2[17] = 0; + array2[18] = 0; + array2[19] = 0; + array2[20] = 0; + array2[21] = 0; + array2[22] = 0; + array2[23] = 0; + array2[24] = 0; + array2[25] = 0; + array2[26] = 0; + array2[27] = 0; + array2[28] = 0; + array2[29] = 0; + array2[30] = 0; + array2[31] = 0; + array2[32] = 0; + array2[33] = 0; + array2[34] = 0; + array2[35] = 0; + array2[36] = 0; + array2[37] = 0; + array2[38] = 0; + array2[39] = 0; + array2[40] = 0; + array2[41] = 0; + array2[42] = 0; + array2[43] = 0; + array2[44] = 0; + array2[45] = 0; + array2[46] = 0; + array2[47] = 0; + array2[48] = 0; + array2[49] = 0; + array2[50] = 0; + array2[51] = 0; + array2[52] = 0; + array2[53] = 0; + array2[54] = 0; + array2[55] = 0; + array2[56] = 0; + array2[57] = 0; + array2[58] = 0; + array2[59] = 0; + array2[60] = 0; + array2[61] = 0; + array2[62] = 0; + array2[63] = 0; + array2[64] = 0; + array2[65] = 0; + array2[66] = 0; + array2[67] = 0; + array2[68] = 0; + array2[69] = 0; + array2[70] = 0; + array2[71] = 0; + array2[72] = 0; + array2[73] = 0; + array2[74] = 0; + array2[75] = 0; + array2[76] = 0; + array2[77] = 0; + array2[78] = 0; + array2[79] = 0; + array2[80] = 0; + array2[81] = 0; + array2[82] = 0; + array2[83] = 0; + array2[84] = 0; + array2[85] = 0; + array2[86] = 0; + array2[87] = 0; + array2[88] = 0; + array2[89] = 0; + array2[90] = 0; + array2[91] = 0; + array2[92] = 0; + array2[93] = 0; + array2[94] = 0; + array2[95] = 0; + array2[96] = 0; + array2[97] = 0; + array2[98] = 0; + array2[99] = 0; + + array2[100] = 0; + array2[101] = 0; + array2[102] = 0; + array2[103] = 0; + array2[104] = 0; + array2[105] = 0; + array2[106] = 0; + array2[107] = 0; + array2[108] = 0; + array2[109] = 0; + array2[110] = 0; + array2[111] = 0; + array2[112] = 0; + array2[113] = 0; + array2[114] = 0; + array2[115] = 0; + array2[116] = 0; + array2[117] = 0; + array2[118] = 0; + array2[119] = 0; + array2[120] = 0; + array2[121] = 0; + array2[122] = 0; + array2[123] = 0; + array2[124] = 0; + array2[125] = 0; + array2[126] = 0; + array2[127] = 0; + array2[128] = 0; + array2[129] = 0; + array2[130] = 0; + array2[131] = 0; + array2[132] = 0; + array2[133] = 0; + array2[134] = 0; + array2[135] = 0; + array2[136] = 0; + array2[137] = 0; + array2[138] = 0; + array2[139] = 0; + array2[140] = 0; + array2[141] = 0; + array2[142] = 0; + array2[143] = 0; + array2[144] = 0; + array2[145] = 0; + array2[146] = 0; + array2[147] = 0; + array2[148] = 0; + array2[149] = 0; + array2[150] = 0; + array2[151] = 0; + array2[152] = 0; + array2[153] = 0; + array2[154] = 0; + array2[155] = 0; + array2[156] = 0; + array2[157] = 0; + array2[158] = 0; + array2[159] = 0; + array2[160] = 0; + array2[161] = 0; + array2[162] = 0; + array2[163] = 0; + array2[164] = 0; + array2[165] = 0; + array2[166] = 0; + array2[167] = 0; + array2[168] = 0; + array2[169] = 0; + array2[170] = 0; + array2[171] = 0; + array2[172] = 0; + array2[173] = 0; + array2[174] = 0; + array2[175] = 0; + array2[176] = 0; + array2[177] = 0; + array2[178] = 0; + array2[179] = 0; + array2[180] = 0; + array2[181] = 0; + array2[182] = 0; + array2[183] = 0; + array2[184] = 0; + array2[185] = 0; + array2[186] = 0; + array2[187] = 0; + array2[188] = 0; + array2[189] = 0; + array2[190] = 0; + array2[191] = 0; + array2[192] = 0; + array2[193] = 0; + array2[194] = 0; + array2[195] = 0; + array2[196] = 0; + array2[197] = 0; + array2[198] = 0; + array2[199] = 0; + i++; + + if (i == stop) { // requires a loop limit predicate + break; + } + } + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/print/PrintInlining.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/print/PrintInlining.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/print/PrintInlining.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/print/PrintInlining.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * 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,14 @@ /* * @test - * @bug 8022585 + * @bug 8022585 8277055 * @summary VM crashes when ran with -XX:+PrintInlining * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining * compiler.print.PrintInlining - * + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining + * compiler.print.PrintInlining + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintIntrinsics + * compiler.print.PrintInlining */ package compiler.print; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java 2022-07-14 08:05:38.000000000 +0000 @@ -27,7 +27,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.instrument - * @requires vm.jvmti + * @requires vm.jvmti & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @build compiler.profiling.spectrapredefineclass.Agent * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.profiling.spectrapredefineclass.Agent * @run driver compiler.profiling.spectrapredefineclass.Launcher diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java 2022-07-14 08:05:38.000000000 +0000 @@ -27,7 +27,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.instrument - * @requires vm.jvmti + * @requires vm.jvmti & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @build compiler.profiling.spectrapredefineclass_classloaders.Agent * compiler.profiling.spectrapredefineclass_classloaders.Test * compiler.profiling.spectrapredefineclass_classloaders.A diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/runtime/Test8168712.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/runtime/Test8168712.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/runtime/Test8168712.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/runtime/Test8168712.java 2022-07-14 08:05:38.000000000 +0000 @@ -22,11 +22,29 @@ */ /** - * @test + * @test id=with-dtrace * @requires vm.debug + * @requires vm.hasDTrace * @bug 8168712 * - * @run main/othervm -XX:CompileCommand=compileonly,Test8168712.* -XX:CompileCommand=compileonly,*Object.* -XX:+DTraceMethodProbes -XX:-UseOnStackReplacement -XX:+DeoptimizeRandom compiler.runtime.Test8168712 + * @run main/othervm -XX:CompileCommand=compileonly,Test8168712.* + * -XX:CompileCommand=compileonly,*Object.* + * -XX:+DTraceMethodProbes + * -XX:-UseOnStackReplacement + * -XX:+DeoptimizeRandom + * compiler.runtime.Test8168712 + */ + +/** + * @test id=without-dtrace + * @requires vm.debug + * @bug 8168712 + * + * @run main/othervm -XX:CompileCommand=compileonly,Test8168712.* + * -XX:CompileCommand=compileonly,*Object.* + * -XX:-UseOnStackReplacement + * -XX:+DeoptimizeRandom + * compiler.runtime.Test8168712 */ package compiler.runtime; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/runtime/TestConstantsInError.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8279822 + * @requires vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm + * + * @run main compiler.runtime.TestConstantsInError + */ +package compiler.runtime; + +import jdk.internal.org.objectweb.asm.*; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleProxies; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.List; + +import static jdk.internal.org.objectweb.asm.ClassWriter.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +interface OutputProcessor { + default void process(OutputAnalyzer output, boolean isC1) {} +} + +public abstract class TestConstantsInError implements OutputProcessor { + static final String TEST_PREFIX = class2desc(TestConstantsInError.class) + "$Test"; + + public interface Test extends Runnable {} + + + interface Generator { + void generate(MethodVisitor mv); + } + + static String class2desc(Class cls) { + return cls.getName().replace('.', '/'); + } + + public static final String PATH = System.getProperty("test.classes", ".") + java.io.File.separator; + + static byte[] generateClassFile(String suffix, Generator g) throws IOException { + var cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES); + String name = TEST_PREFIX + "_" + suffix; + cw.visit(V17, ACC_PUBLIC | ACC_SUPER, name, null, "java/lang/Object", null); + + { + var mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", "()V", null, null); + mv.visitCode(); + g.generate(mv); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + } + byte[] classFile = cw.toByteArray(); + + try (FileOutputStream fos = new FileOutputStream(PATH + name + ".class")) { + fos.write(classFile); + } + + return classFile; + } + + static Test generate(String suffix, Class expectedError, Generator g) { + try { + byte[] classFile = generateClassFile(suffix, g); + MethodHandles.Lookup testLookup = MethodHandles.lookup().defineHiddenClass(classFile, true); + MethodHandle testMH = testLookup.findStatic(testLookup.lookupClass(), "test", MethodType.methodType(void.class)); + + testMH = MethodHandles.filterReturnValue(testMH, + MethodHandles.insertArguments( + MethodHandles.throwException(void.class, AssertionError.class), + 0, new AssertionError("no exception thrown"))); + + // Install empty handler for linkage exceptions. + testMH = MethodHandles.catchException(testMH, expectedError, + MethodHandles.empty(MethodType.methodType(void.class, expectedError))); + + return MethodHandleProxies.asInterfaceInstance(Test.class, testMH); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + static void run(String name, Class expectedError, Generator g) { + Test test = generate(name, expectedError, g); + for (int i = 0; i < 1000; i++) { + test.run(); + } + } + + static class TestConstantClass extends TestConstantsInError { + public static void main(String[] args) { + run("C1", NoClassDefFoundError.class, mv -> mv.visitLdcInsn(Type.getType("LUnknownClass;"))); // non-existent class + run("C2", IllegalAccessError.class, mv -> mv.visitLdcInsn(Type.getType("Ljava/lang/invoke/LambdaForm;"))); // inaccessible + + // class loader constraints? + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_C1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_C2/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_C1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_C2/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + + public void processC2(OutputAnalyzer results) { + results.shouldNotContain("made not entrant"); + } + } + + static class TestConstantMethodHandle extends TestConstantsInError { + public static void main(String[] args) { + // Non-existent holder class + run("MH1", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "UnknownClass", "ignored", "()V", false))); + + // Inaccessible holder class + run("MH2", IllegalAccessError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/invoke/LambdaForm", "ignored", "()V", false))); + + // Method vs InterfaceMethod mismatch + run("MH3", IncompatibleClassChangeError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/Object", "ignored", "()V", true))); + + // Non-existent method + run("MH4", NoSuchMethodError.class, + mv -> mv.visitLdcInsn(new Handle(H_INVOKESTATIC, "java/lang/Object", "cast", "()V", false))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_MH1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH2/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH3/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MH4/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_MH1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH2/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH3/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MH4/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + } + + static class TestConstantMethodType extends TestConstantsInError { + public static void main(String[] args) { + run("MT1", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(Type.getMethodType("(LUnknownClass;)V"))); + run("MT2", NoClassDefFoundError.class, + mv -> mv.visitLdcInsn(Type.getMethodType("()LUnknownClass;"))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + results.shouldMatch("Test_MT1/.*::test \\(3 bytes\\)$") + .shouldMatch("Test_MT2/.*::test \\(3 bytes\\)$"); + + if (isC1 && Platform.isAArch64()) { // no code patching + results.shouldMatch("Test_MT1/.*::test \\(3 bytes\\) made not entrant") + .shouldMatch("Test_MT2/.*::test \\(3 bytes\\) made not entrant"); + } else { + results.shouldNotContain("made not entrant"); + } + } + } + + static class TestConstantDynamic extends TestConstantsInError { + static int bsm1() throws Exception { + throw new AssertionError("should not be invoked"); + } + + static int bsm2(MethodHandles.Lookup lookup, String name, Class c) throws Exception { + throw new Exception("expected"); + } + + static final Handle BSM1 = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "bsm1", "()I", false); + static final Handle BSM2 = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "bsm2", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)I", + false); + + public static void main(String[] args) { + run("CD1", NoClassDefFoundError.class, + mv -> { + Handle bsm = new Handle(H_INVOKESTATIC, "UnknownClass", "unknown", "()LUnknownClass;", false); + mv.visitLdcInsn(new ConstantDynamic("tmp", "LUnknownClass;", bsm)); + }); + run("CD2", NoSuchMethodError.class, + mv -> { + Handle bsm = new Handle(H_INVOKESTATIC, class2desc(TestConstantDynamic.class), "unknown", "()I", false); + mv.visitLdcInsn(new ConstantDynamic("tmp", "LUnknownClass;", bsm)); + }); + run("CD3", BootstrapMethodError.class, mv -> mv.visitLdcInsn(new ConstantDynamic("tmp", "I", BSM1))); + run("CD4", BootstrapMethodError.class, mv -> mv.visitLdcInsn(new ConstantDynamic("tmp", "I", BSM2))); + } + + public void process(OutputAnalyzer results, boolean isC1) { + if (isC1) { + results.shouldMatch("Test_CD1.*::test \\(3 bytes\\) COMPILE SKIPPED: could not resolve a constant") + .shouldMatch("Test_CD2.*::test \\(3 bytes\\) COMPILE SKIPPED: could not resolve a constant") + .shouldMatch("Test_CD3.*::test \\(3 bytes\\) COMPILE SKIPPED: could not resolve a constant") + .shouldMatch("Test_CD4.*::test \\(3 bytes\\) COMPILE SKIPPED: could not resolve a constant"); + } else { + results.shouldMatch("Test_CD1.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD2.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD3.*::test \\(3 bytes\\)$") + .shouldMatch("Test_CD4.*::test \\(3 bytes\\)$"); + } + } + } + + static void run(TestConstantsInError test) throws Exception { + List commonArgs = List.of( + "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED", + "-Xbatch", "-XX:CompileThreshold=100", + "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,*::test", + "-XX:+PrintCompilation", + "-XX:CompileCommand=print,*::test", + "-Dtest.classes=" + System.getProperty("test.classes", "."), + "-XX:+IgnoreUnrecognizedVMOptions", + test.getClass().getName()); + + ArrayList c1Args = new ArrayList<>(); + c1Args.addAll(List.of("-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-XX:+TracePatching")); + c1Args.addAll(commonArgs); + + OutputAnalyzer outputC1 = ProcessTools.executeTestJvm(c1Args) + .shouldHaveExitValue(0); + + test.process(outputC1, true); + + ArrayList c2Args = new ArrayList<>(); + c2Args.add("-XX:-TieredCompilation"); + c2Args.addAll(commonArgs); + + OutputAnalyzer outputC2 = ProcessTools.executeTestJvm(c2Args) + .shouldHaveExitValue(0); + + test.process(outputC2, false); + } + + public static void main(String[] args) throws Exception { + run(new TestConstantClass()); + run(new TestConstantMethodType()); + run(new TestConstantMethodHandle()); + run(new TestConstantDynamic()); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/stable/TestStableShort.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/stable/TestStableShort.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/stable/TestStableShort.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/stable/TestStableShort.java 2022-07-14 08:05:38.000000000 +0000 @@ -37,18 +37,18 @@ * @run main/bootclasspath/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 * -XX:-TieredCompilation - * -XX:+FoldStableValues + * -XX:-FoldStableValues * compiler.stable.TestStableShort * * @run main/bootclasspath/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * -XX:-TieredCompilation + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 * -XX:+FoldStableValues * compiler.stable.TestStableShort * @run main/bootclasspath/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * -XX:-TieredCompilation - * -XX:+FoldStableValues + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:-FoldStableValues * compiler.stable.TestStableShort */ diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.vectorapi; + +import java.util.Random; +import jdk.incubator.vector.ByteVector; +import jdk.incubator.vector.DoubleVector; +import jdk.incubator.vector.ShortVector; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +/* + * @test + * @bug 8278948 + * @summary Intermediate integer promotion vector length encoding is calculated incorrectly on x86 + * @modules jdk.incubator.vector + * @library /test/lib + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:CompileThreshold=100 -XX:UseAVX=1 + * compiler.vectorapi.Test8278948 + */ +public class Test8278948 { + static final int INVOCATIONS = 10000; + + static final Random random = Utils.getRandomInstance(); + static final byte[] BYTES = new byte[8]; + static final short[] SHORTS = new short[4]; + static final double[] DOUBLES = new double[4]; + + + public static void main(String[] args) { + for (int i = 0; i < INVOCATIONS; i++) { + for (int j = 0; j < DOUBLES.length; j++) { + BYTES[j] = (byte)random.nextInt(); + } + bytesToDoubles(); + for (int j = 0; j < DOUBLES.length; j++) { + Asserts.assertEquals((double)BYTES[j], DOUBLES[j]); + } + + for (int j = 0; j < DOUBLES.length; j++) { + SHORTS[j] = (short)random.nextInt(); + } + shortsToDoubles(); + for (int j = 0; j < DOUBLES.length; j++) { + Asserts.assertEquals((double)SHORTS[j], DOUBLES[j]); + } + } + } + + static void bytesToDoubles() { + ((DoubleVector)ByteVector.fromArray(ByteVector.SPECIES_64, BYTES, 0) + .castShape(DoubleVector.SPECIES_256, 0)) + .intoArray(DOUBLES, 0); + } + + static void shortsToDoubles() { + ((DoubleVector)ShortVector.fromArray(ShortVector.SPECIES_64, SHORTS, 0) + .castShape(DoubleVector.SPECIES_256, 0)) + .intoArray(DOUBLES, 0); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/containers/docker/TestMisc.java openjdk-17-17.0.4+8/test/hotspot/jtreg/containers/docker/TestMisc.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/containers/docker/TestMisc.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/containers/docker/TestMisc.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ testMinusContainerSupport(); testIsContainerized(); testPrintContainerInfo(); + testPrintContainerInfoActiveProcessorCount(); } finally { DockerTestUtils.removeDockerImage(imageName); } @@ -92,6 +93,15 @@ checkContainerInfo(Common.run(opts)); } + private static void testPrintContainerInfoActiveProcessorCount() throws Exception { + Common.logNewTestCase("Test print_container_info()"); + + DockerRunOptions opts = Common.newOpts(imageName, "PrintContainerInfo").addJavaOpts("-XX:ActiveProcessorCount=2"); + Common.addWhiteBoxOpts(opts); + + OutputAnalyzer out = Common.run(opts); + out.shouldContain("but overridden by -XX:ActiveProcessorCount 2"); + } private static void checkContainerInfo(OutputAnalyzer out) throws Exception { String[] expectedToContain = new String[] { diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/g1/mixedgc/TestOldGenCollectionUsage.java openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/g1/mixedgc/TestOldGenCollectionUsage.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/g1/mixedgc/TestOldGenCollectionUsage.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/g1/mixedgc/TestOldGenCollectionUsage.java 2022-07-14 08:05:38.000000000 +0000 @@ -139,8 +139,8 @@ if (newCollectionCount <= collectionCount) { throw new RuntimeException("No new collection"); } - if (newCollectionTime <= collectionTime) { - throw new RuntimeException("Collector has not run some more"); + if (newCollectionTime < collectionTime) { + throw new RuntimeException("Collection time ran backwards"); } System.out.println("Test passed."); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/g1/plab/lib/LogParser.java openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/g1/plab/lib/LogParser.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/g1/plab/lib/LogParser.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/g1/plab/lib/LogParser.java 2022-07-14 08:05:38.000000000 +0000 @@ -190,13 +190,17 @@ } private Map getSpecifiedStats(List gcIds, LogParser.ReportType type, List fieldNames, boolean extractId) { - return new HashMap<>( - getEntries().entryStream() - .filter(gcLogItem -> extractId == gcIds.contains(gcLogItem.getKey())) - .collect(Collectors.toMap(gcLogItem -> gcLogItem.getKey(), - gcLogItem -> gcLogItem.getValue().get(type).filter(fieldNames) + var map = new HashMap<>( + getEntries().entryStream() + .filter(gcLogItem -> extractId == gcIds.contains(gcLogItem.getKey())) + .collect(Collectors.toMap(gcLogItem -> gcLogItem.getKey(), + gcLogItem -> gcLogItem.getValue().get(type).filter(fieldNames) + ) ) - ) - ); + ); + if (map.isEmpty()) { + throw new RuntimeException("Cannot find relevant PLAB statistics in the log"); + } + return map; } } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/g1/plab/TestPLABEvacuationFailure.java openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/g1/plab/TestPLABEvacuationFailure.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/g1/plab/TestPLABEvacuationFailure.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/g1/plab/TestPLABEvacuationFailure.java 2022-07-14 08:05:38.000000000 +0000 @@ -68,7 +68,7 @@ "failure wasted")); private static final String[] COMMON_OPTIONS = { - "-Xlog:gc=debug,gc+phases=trace", + "-Xlog:gc,gc+plab=debug", "-XX:+UseG1GC", "-XX:InitiatingHeapOccupancyPercent=100", "-XX:-G1UseAdaptiveIHOP", diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierAboveProj.java openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierAboveProj.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierAboveProj.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierAboveProj.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 8281811 + * @summary assert(_base == Tuple) failed: Not a Tuple after JDK-8280799 + * @requires vm.gc.Shenandoah + * @run main/othervm -XX:+UseShenandoahGC -XX:-BackgroundCompilation -XX:LoopMaxUnroll=1 TestBarrierAboveProj + */ + + +public class TestBarrierAboveProj { + private static C objField = new C(); + private static final Object[] arrayField = new Object[1000]; + private static volatile int volatileField; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(); + test2(); + } + } + + private static float test1() { + float v = 1; + for (int i = 1; i < 1000; i++) { + if (objField == arrayField[i]) { + return v; + } + v *= 2; + } + return v; + } + + private static float test2() { + float v = 1; + volatileField = 0x42; + for (int i = 1; i < 1000; i++) { + if (objField == arrayField[i]) { + return v; + } + v *= 2; + } + return v; + } + + private static class C { + public float floatField; + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/TestSystemGC.java openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/TestSystemGC.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/gc/TestSystemGC.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/gc/TestSystemGC.java 2022-07-14 08:05:38.000000000 +0000 @@ -24,35 +24,48 @@ package gc; /* - * @test TestSystemGCSerial + * @test id=Serial * @requires vm.gc.Serial * @summary Runs System.gc() with different flags. * @run main/othervm -XX:+UseSerialGC gc.TestSystemGC + * @run main/othervm -XX:+UseSerialGC -XX:+UseLargePages gc.TestSystemGC */ /* - * @test TestSystemGCParallel + * @test id=Parallel * @requires vm.gc.Parallel * @summary Runs System.gc() with different flags. * @run main/othervm -XX:+UseParallelGC gc.TestSystemGC + * @run main/othervm -XX:+UseParallelGC -XX:+UseLargePages gc.TestSystemGC */ /* - * @test TestSystemGCG1 + * @test id=G1 * @requires vm.gc.G1 * @summary Runs System.gc() with different flags. * @run main/othervm -XX:+UseG1GC gc.TestSystemGC * @run main/othervm -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent gc.TestSystemGC - * @run main/othervm -XX:+UseLargePages gc.TestSystemGC - */ + * @run main/othervm -XX:+UseG1GC -XX:+UseLargePages gc.TestSystemGC + */ /* - * @test TestSystemGCShenandoah + * @test id=Shenandoah * @requires vm.gc.Shenandoah * @summary Runs System.gc() with different flags. - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC gc.TestSystemGC - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+ExplicitGCInvokesConcurrent gc.TestSystemGC + * @run main/othervm -XX:+UseShenandoahGC gc.TestSystemGC + * @run main/othervm -XX:+UseShenandoahGC -XX:+ExplicitGCInvokesConcurrent gc.TestSystemGC + * @run main/othervm -XX:+UseShenandoahGC -XX:+UseLargePages gc.TestSystemGC + */ + +/* + * @test id=Z + * @requires vm.gc.Z + * @comment ZGC will not start when LargePages cannot be allocated, therefore + * we do not run such configuration. + * @summary Runs System.gc() with different flags. + * @run main/othervm -XX:+UseZGC gc.TestSystemGC */ + public class TestSystemGC { public static void main(String args[]) throws Exception { System.gc(); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/ProblemList.txt openjdk-17-17.0.4+8/test/hotspot/jtreg/ProblemList.txt --- openjdk-17-17.0.3+7/test/hotspot/jtreg/ProblemList.txt 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/ProblemList.txt 2022-07-14 08:05:38.000000000 +0000 @@ -154,7 +154,6 @@ vmTestbase/nsk/jvmti/scenarios/jni_interception/JI05/ji05t001/TestDescription.java 8219652 aix-ppc64 vmTestbase/nsk/jvmti/scenarios/jni_interception/JI06/ji06t001/TestDescription.java 8219652 aix-ppc64 vmTestbase/nsk/jvmti/SetJNIFunctionTable/setjniftab001/TestDescription.java 8219652 aix-ppc64 -vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003/TestDescription.java 8264605 generic-all vmTestbase/nsk/jvmti/PopFrame/popframe011/TestDescription.java 8266593 generic-all vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8192647 generic-all diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/resourcehogs/compiler/intrinsics/string/TestStringIntrinsics2LargeArray.java openjdk-17-17.0.4+8/test/hotspot/jtreg/resourcehogs/compiler/intrinsics/string/TestStringIntrinsics2LargeArray.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/resourcehogs/compiler/intrinsics/string/TestStringIntrinsics2LargeArray.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/resourcehogs/compiler/intrinsics/string/TestStringIntrinsics2LargeArray.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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 8254790 + * @requires vm.bits == "64" & os.maxMemory > 8G + * @modules java.base/jdk.internal.misc + * @library /test/lib /test/hotspot/jtreg + * + * @build compiler.intrinsics.string.TestStringIntrinsics2 + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * + * @run main/othervm + * -mx8G + * -Xbootclasspath/a:. + * -Xmixed + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:MaxInlineSize=70 + * -XX:MinInlineFrequencyRatio=0 + * resourcehogs.compiler.intrinsics.string.TestStringIntrinsics2LargeArray + */ + +package resourcehogs.compiler.intrinsics.string; + +import java.lang.ref.Reference; + +import compiler.intrinsics.string.TestStringIntrinsics2; + +public final class TestStringIntrinsics2LargeArray { + public static void main(String[] args) throws Exception { + int[] hugeArray = new int[Integer.MAX_VALUE / 2]; + TestStringIntrinsics2.main(args); + Reference.reachabilityFence(hugeArray); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,6 +79,7 @@ public static final String RETAINS_FD = "VM RESULT => RETAINS FD"; public static final String EXIT = "VM RESULT => VM EXIT"; public static final String LOG_SUFFIX = ".strangelogsuffixthatcanbecheckedfor"; + public static final String USER_DIR = System.getProperty("user.dir"); // first VM public static void main(String[] args) throws Exception { @@ -187,10 +188,10 @@ static Collection outputContainingFilenames() { long pid = ProcessHandle.current().pid(); - String[] command = lsofCommand().orElseThrow(() -> new RuntimeException("lsof like command not found")); - System.out.println("using command: " + command[0] + " " + command[1]); - return run(command[0], command[1], "" + pid).collect(toList()); + // Only search the directory in which the VM is running (user.dir property). + System.out.println("using command: " + command[0] + " -a +d " + USER_DIR + " " + command[1] + " " + pid); + return run(command[0], "-a", "+d", USER_DIR, command[1], "" + pid).collect(toList()); } static boolean findOpenLogFile(Collection fileNames) { diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java 2022-07-14 08:05:38.000000000 +0000 @@ -31,7 +31,8 @@ * @build sun.hotspot.WhiteBox * @compile test-classes/Hello.java * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SharedArchiveConsistency + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SharedArchiveConsistency on + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SharedArchiveConsistency auto */ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Utils; @@ -69,6 +70,9 @@ public static int int_size; // size of int public static long alignment; // MetaspaceShared::core_region_alignment + public static boolean shareAuto; // true == -Xshare:auto + // false == -Xshare:on + // The following should be consistent with the enum in the C++ MetaspaceShared class public static String[] shared_region_name = { "rw", // ReadWrite @@ -80,6 +84,8 @@ "last_open_archive" }; + public static final String HELLO_WORLD = "Hello World"; + public static int num_regions = shared_region_name.length; public static String[] matchMessages = { "Unable to use shared archive", @@ -339,7 +345,7 @@ } public static void testAndCheck(String[] execArgs) throws Exception { - OutputAnalyzer output = TestCommon.execCommon(execArgs); + OutputAnalyzer output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); String stdtxt = output.getOutput(); System.out.println("Note: this test may fail in very rare occasions due to CRC32 checksum collision"); for (String message : matchMessages) { @@ -361,6 +367,14 @@ // 6) insert bytes in data begining // 7) randomly corrupt data in each region specified by shared_region_name[] public static void main(String... args) throws Exception { + if (args.length != 1) { + throw new RuntimeException("One arg of 'on' or 'auto' to run the test"); + } + if (!args[0].equals("on") && !args[0].equals("auto")) { + throw new RuntimeException("Arg must be 'on' or 'auto'"); + } + shareAuto = args[0].equals("auto"); + // must call to get offset info first!!! getFileOffsetInfo(); Path currentRelativePath = Paths.get(""); @@ -380,10 +394,10 @@ // VerifySharedSpaces enabled to detect inconsistencies String[] verifyExecArgs = {"-Xlog:cds", "-XX:+VerifySharedSpaces", "-cp", jarFile, "Hello"}; - OutputAnalyzer output = TestCommon.execCommon(execArgs); + OutputAnalyzer output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); try { - TestCommon.checkExecReturn(output, 0, true, "Hello World"); + TestCommon.checkExecReturn(output, 0, true, HELLO_WORLD); } catch (Exception e) { TestCommon.checkExecReturn(output, 1, true, matchMessages[0]); } @@ -397,36 +411,42 @@ // modify jsa header, test should fail System.out.println("\n2. Corrupt header, should fail\n"); modifyJsaHeader(copyFile(orgJsaFile, "corrupt-header")); - output = TestCommon.execCommon(execArgs); + output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has a bad magic number"); output.shouldNotContain("Checksum verification failed"); + if (shareAuto) { + output.shouldContain(HELLO_WORLD); + } // modify _jvm_ident, test should fail System.out.println("\n2a. Corrupt _jvm_ident, should fail\n"); modifyJvmIdent(copyFile(orgJsaFile, "modify-jvm-ident")); - output = TestCommon.execCommon(execArgs); + output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file was created by a different version or build of HotSpot"); output.shouldNotContain("Checksum verification failed"); - - // use the same archive as above, but run with -Xshare:auto - System.out.println("\n2b. Corrupt _jvm_ident run with -Xshare:auto\n"); - output = TestCommon.execAuto(execArgs); - output.shouldContain("The shared archive file was created by a different version or build of HotSpot"); - output.shouldContain("Hello World"); + if (shareAuto) { + output.shouldContain(HELLO_WORLD); + } // modify _magic, test should fail System.out.println("\n2c. Corrupt _magic, should fail\n"); modifyHeaderIntField(copyFile(orgJsaFile, "modify-magic"), offset_magic, 0x00000000); - output = TestCommon.execCommon(execArgs); + output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has a bad magic number"); output.shouldNotContain("Checksum verification failed"); + if (shareAuto) { + output.shouldContain(HELLO_WORLD); + } // modify _version, test should fail System.out.println("\n2d. Corrupt _version, should fail\n"); modifyHeaderIntField(copyFile(orgJsaFile, "modify-version"), offset_version, 0x00000000); - output = TestCommon.execCommon(execArgs); + output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has the wrong version"); output.shouldNotContain("Checksum verification failed"); + if (shareAuto) { + output.shouldContain(HELLO_WORLD); + } // modify content inside regions System.out.println("\n3. Corrupt Content, should fail\n"); @@ -442,9 +462,12 @@ File newJsaFile = copyFile(orgJsaFile, "header-and-content"); modifyJsaHeader(newJsaFile); modifyJsaContent(0, newJsaFile); // this will not be reached since failed on header change first - output = TestCommon.execCommon(execArgs); + output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has a bad magic number"); output.shouldNotContain("Checksum verification failed"); + if (shareAuto) { + output.shouldContain(HELLO_WORLD); + } // delete bytes in data section System.out.println("\n5. Delete bytes at beginning of data section, should fail\n"); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java 2022-07-14 08:05:38.000000000 +0000 @@ -223,8 +223,8 @@ "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000"); - if (!Platform.isAArch64()) { - // Currently relax this test for Aarch64. + if (!Platform.isAArch64() && !Platform.isPPC()) { + // Currently relax this test for Aarch64 and ppc. output.shouldContain("Narrow klass shift: 0"); } output.shouldHaveExitValue(0); @@ -243,8 +243,8 @@ "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000"); - if (!Platform.isAArch64()) { - // Currently relax this test for Aarch64. + if (!Platform.isAArch64() && !Platform.isPPC()) { + // Currently relax this test for Aarch64 and ppc. output.shouldContain("Narrow klass shift: 0"); } output.shouldHaveExitValue(0); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/EnclosingMethodAttr/EnclMethodAttr.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/EnclosingMethodAttr/EnclMethodAttr.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/EnclosingMethodAttr/EnclMethodAttr.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/EnclosingMethodAttr/EnclMethodAttr.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * 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,6 +44,7 @@ System.out.println("Regression test for bug 8044738"); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("EnclMethTest"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); output.shouldContain("java.lang.ClassFormatError: Wrong EnclosingMethod"); } } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/execstack/TestCheckJDK.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/execstack/TestCheckJDK.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/execstack/TestCheckJDK.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/execstack/TestCheckJDK.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * 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,7 +48,7 @@ static void checkExecStack(Path file) { String filename = file.toString(); Path parent = file.getParent(); - if (parent.endsWith("bin") || filename.endsWith(".so")) { + if ((parent.endsWith("bin") && !filename.endsWith(".diz")) || filename.endsWith(".so")) { if (!WB.checkLibSpecifiesNoexecstack(filename)) { System.out.println("Library does not have the noexecstack bit set: " + filename); testPassed = false; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/jni/FastGetField/libFastGetField.c openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/jni/FastGetField/libFastGetField.c --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/jni/FastGetField/libFastGetField.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/jni/FastGetField/libFastGetField.c 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 SAP SE and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 SAP SE and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,7 +119,7 @@ JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { jvmtiCapabilities capa; - jvmtiEventCallbacks cbs = {0}; + jvmtiEventCallbacks cbs; (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0); @@ -127,6 +127,7 @@ capa.can_generate_field_access_events = 1; (*jvmti)->AddCapabilities(jvmti, &capa); + memset(&cbs, 0, sizeof(cbs)); cbs.FieldAccess = &onFieldAccess; (*jvmti)->SetEventCallbacks(jvmti, &cbs, sizeof(cbs)); (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_ACCESS, NULL); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/ClassInitializationTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/ClassInitializationTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/ClassInitializationTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/ClassInitializationTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ "-Xmx128m", "BadMap50"); OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldNotHaveExitValue(0); out.shouldContain("Start class verification for:"); out.shouldContain("End class verification for:"); out.shouldContain("Initializing"); @@ -69,6 +70,7 @@ "-Xmx128m", "BadMap50"); out = new OutputAnalyzer(pb.start()); + out.shouldNotHaveExitValue(0); out.shouldNotContain("[class,init]"); out.shouldNotContain("Fail over class verification to old verifier for: BadMap50"); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/ClassResolutionTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/ClassResolutionTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/ClassResolutionTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/ClassResolutionTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,7 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:class+resolve=debug", ClassResolutionTestMain.class.getName()); OutputAnalyzer o = new OutputAnalyzer(pb.start()); + o.shouldHaveExitValue(0); o.shouldContain("[class,resolve] ClassResolutionTest$ClassResolutionTestMain$Thing1Handler ClassResolutionTest$ClassResolutionTestMain$Thing1"); o.shouldContain("[class,resolve] resolve JVM_CONSTANT_MethodHandle"); @@ -70,6 +71,7 @@ "-Xlog:class+resolve=off", ClassResolutionTestMain.class.getName()); o = new OutputAnalyzer(pb.start()); + o.shouldHaveExitValue(0); o.shouldNotContain("[class,resolve]"); }; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/CondyIndyTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/CondyIndyTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/CondyIndyTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/CondyIndyTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * 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,6 +42,7 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:methodhandles", "CondyIndy"); OutputAnalyzer o = new OutputAnalyzer(pb.start()); + o.shouldHaveExitValue(0); o.shouldContain("[info][methodhandles"); o.shouldNotContain("[debug][methodhandles,indy"); o.shouldNotContain("[debug][methodhandles,condy"); @@ -50,6 +51,7 @@ pb = ProcessTools.createJavaProcessBuilder("-Xlog:methodhandles+condy=debug", "CondyIndy"); o = new OutputAnalyzer(pb.start()); + o.shouldHaveExitValue(0); o.shouldNotContain("[info ][methodhandles"); o.shouldNotContain("[debug][methodhandles,indy"); o.shouldContain("[debug][methodhandles,condy"); @@ -58,6 +60,7 @@ pb = ProcessTools.createJavaProcessBuilder("-Xlog:methodhandles+indy=debug", "CondyIndy"); o = new OutputAnalyzer(pb.start()); + o.shouldHaveExitValue(0); o.shouldNotContain("[info ][methodhandles"); o.shouldContain("[debug][methodhandles,indy"); o.shouldNotContain("[debug][methodhandles,condy"); @@ -68,6 +71,7 @@ "-Xlog:methodhandles+indy=debug", "CondyIndy"); o = new OutputAnalyzer(pb.start()); + o.shouldHaveExitValue(0); o.shouldContain("[info ][methodhandles"); o.shouldContain("[debug][methodhandles,indy"); o.shouldContain("[debug][methodhandles,condy"); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/LoaderConstraintsTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/LoaderConstraintsTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/LoaderConstraintsTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/LoaderConstraintsTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -27,6 +27,7 @@ * @bug 8149996 * @modules java.base/jdk.internal.misc * @library /test/lib classes + * @build test.Empty * @run driver LoaderConstraintsTest */ @@ -68,11 +69,13 @@ // -Xlog:class+loader+constraints=info pb = exec("-Xlog:class+loader+constraints=info"); out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); out.shouldContain("[class,loader,constraints] adding new constraint for name: java/lang/Class, loader[0]: 'app', loader[1]: 'bootstrap'"); // -Xlog:class+loader+constraints=off pb = exec("-Xlog:class+loader+constraints=off"); out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); out.shouldNotContain("[class,loader,constraints]"); } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/MonitorMismatchTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/MonitorMismatchTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/MonitorMismatchTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/MonitorMismatchTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * 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,6 +44,7 @@ "-Xlog:monitormismatch=info", "MonitorMismatchHelper"); OutputAnalyzer o = new OutputAnalyzer(pb.start()); + o.shouldHaveExitValue(0); o.shouldContain("[monitormismatch] Monitor mismatch in method"); // monitormismatch should turn off. @@ -52,6 +53,7 @@ "-Xlog:monitormismatch=off", "MonitorMismatchHelper"); o = new OutputAnalyzer(pb.start()); + o.shouldHaveExitValue(0); o.shouldNotContain("[monitormismatch]"); }; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/ThreadLoggingTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/ThreadLoggingTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/logging/ThreadLoggingTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/logging/ThreadLoggingTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -41,7 +41,7 @@ public class ThreadLoggingTest { static void analyzeOutputForInfoLevel(OutputAnalyzer output) throws Exception { - output.shouldContain("Thread started"); + output.shouldMatch("Thread .* started"); output.shouldContain("Thread is alive"); output.shouldContain("Thread finished"); output.shouldHaveExitValue(0); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/Monitor/MonitorUsedDeflationThresholdTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/Monitor/MonitorUsedDeflationThresholdTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/Monitor/MonitorUsedDeflationThresholdTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/Monitor/MonitorUsedDeflationThresholdTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -80,6 +80,11 @@ // of monitors for threads that call Object.wait(). "-XX:+UnlockDiagnosticVMOptions", "-XX:AvgMonitorsPerThreadEstimate=1", + // MonitorUsedDeflationThreshold == 10 means we'll request + // deflations when 10% of monitors are used rather than the + // default 90%. This should allow the test to tolerate a burst + // of used monitors by threads not under this test's control. + "-XX:MonitorUsedDeflationThreshold=10", // Enable monitorinflation logging so we can see that // MonitorUsedDeflationThreshold and // NoAsyncDeflationProgressMaxoption are working. @@ -88,8 +93,9 @@ "-Xlog:safepoint+cleanup=info", "-Xlog:safepoint+stats=debug", // Run the test with inflate_count == 33 since that - // reproduced the bug with JDK13. Anything above the - // in_use_list_ceiling will do the trick. + // reproduced the bug with JDK13. With inflate_count == 33, an + // initial ceiling == 12 and MonitorUsedDeflationThreshold == 10, + // we should hit NoAsyncDeflationProgressMax at least 3 times. "MonitorUsedDeflationThresholdTest", "33"); OutputAnalyzer output_detail = new OutputAnalyzer(pb.start()); @@ -110,6 +116,8 @@ throw new RuntimeException("Did not find too_many string in output.\n"); } System.out.println("too_many='" + too_many + "'"); + // Uncomment the following line for dumping test output in passing runs: + // output_detail.reportDiagnosticSummary(); System.out.println("PASSED."); return; diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/Nestmates/protectionDomain/TestDifferentProtectionDomains.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/Nestmates/protectionDomain/TestDifferentProtectionDomains.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/Nestmates/protectionDomain/TestDifferentProtectionDomains.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/Nestmates/protectionDomain/TestDifferentProtectionDomains.java 2022-07-14 08:05:38.000000000 +0000 @@ -29,7 +29,8 @@ * perform a nestmate access check. * @comment We use WB to force-compile a constructor to recreate the original * failure scenario, so only run when we have "normal" compiler flags. - * @requires vm.compMode=="Xmixed" & + * @requires vm.compMode == "Xmixed" & + * vm.compiler2.enabled & * (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @library /test/lib / * @build sun.hotspot.WhiteBox @@ -110,7 +111,9 @@ // Force the constructor to compile, which then triggers the nestmate // access check in the compiler thread, which leads to the original bug. - wb.enqueueMethodForCompilation(cons, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + if (!wb.enqueueMethodForCompilation(cons, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) { + throw new RuntimeException("Failed to queue constructor for compilation"); + } while (!wb.isMethodCompiled(cons)) { Thread.sleep(100); } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/ClassBuilder.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/ClassBuilder.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/ClassBuilder.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/ClassBuilder.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,7 +112,7 @@ int packageId = classdata.get(classId).packageId.ordinal(); Clazz C = helpers[packageId]; if (C == null) { - C = new Clazz(getPackageName(packageId) + "Helper", -1, ACC_PUBLIC); + C = new Clazz(getPackageName(packageId) + "Helper", ACC_PUBLIC, -1); helpers[packageId] = C; classes.add(C); } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/Clazz.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/Clazz.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/Clazz.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/Clazz.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 +69,7 @@ * @param implementing Interfaces implemented */ public Clazz(String name, String extending, int access, int classFileVersion, int index, String... implementing) { - super(name, extending == null ? "java/lang/Object" : extending, access + ACC_SUPER, classFileVersion, index, implementing); + super(name, extending == null ? "java/lang/Object" : extending, access | ACC_SUPER, classFileVersion, index, implementing); // Add the default constructor addMethod("", "()V", ACC_PUBLIC).makeConstructor(extending, false); } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/TestBuilder.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/TestBuilder.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/TestBuilder.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/TestBuilder.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 +36,7 @@ super(testcase); // Make a public class Test that contains all our test methods - testClass = new Clazz("Test", null, -1, ACC_PUBLIC); + testClass = new Clazz("Test", null, ACC_PUBLIC, -1); // Add a main method mainMethod = testClass.addMethod("main", "([Ljava/lang/String;)V", ACC_PUBLIC + ACC_STATIC); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/Thread/Fibonacci.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/Thread/Fibonacci.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/Thread/Fibonacci.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/Thread/Fibonacci.java 2022-07-14 08:05:38.000000000 +0000 @@ -28,6 +28,7 @@ * This test is skipped on 32-bit Windows: limited virtual space on Win-32 * make this test inherently unstable on Windows with 32-bit VM data model. * @requires !(os.family == "windows" & sun.arch.data.model == "32") + * @requires !(os.family == "linux" & os.maxMemory < 512M) * @modules java.base/jdk.internal.misc * @library /test/lib * @run main/othervm Fibonacci 15 diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/verifier/TestSigParse.java openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/verifier/TestSigParse.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/runtime/verifier/TestSigParse.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/runtime/verifier/TestSigParse.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * 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 8129579 + * @bug 8219579 * @summary Test that signatures are properly parsed when verification of local * classes is requested but verification of remote classes is not. * @compile BadSignatures.jcod @@ -33,7 +33,7 @@ public class TestSigParse { public static void main(String args[]) throws Throwable { - System.out.println("Regression test for bug 819579"); + System.out.println("Regression test for bug 8219579"); // Test a FieldRef with a bad signature. try { diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/7170638/SDTProbesGNULinuxTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -28,6 +28,7 @@ * @summary Test SDT probes available on GNU/Linux when DTRACE_ENABLED * @requires os.family == "linux" * @requires vm.flagless + * @requires vm.hasDTrace * * @library /test/lib * @run driver SDTProbesGNULinuxTest @@ -36,7 +37,6 @@ import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jtreg.SkippedException; import java.nio.file.Files; import java.nio.file.Path; @@ -44,17 +44,7 @@ public class SDTProbesGNULinuxTest { public static void main(String[] args) throws Throwable { - { - var pb = ProcessTools.createJavaProcessBuilder( - "-XX:+ExtendedDTraceProbes", - "-version"); - var oa = new OutputAnalyzer(pb.start()); - // This test only matters when build with DTRACE_ENABLED. - if (oa.getExitValue() != 0) { - throw new SkippedException("Not build using DTRACE_ENABLED"); - } - } - + // This test only matters when build with DTRACE_ENABLED. try (var libjvms = Files.walk(Paths.get(Utils.TEST_JDK))) { libjvms.filter(p -> "libjvm.so".equals(p.getFileName().toString())) .map(Path::toAbsolutePath) diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/dcmd/jvmti/AttachFailed/AttachReturnError.java openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/dcmd/jvmti/AttachFailed/AttachReturnError.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/dcmd/jvmti/AttachFailed/AttachReturnError.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/dcmd/jvmti/AttachFailed/AttachReturnError.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,8 @@ /* * @test * @bug 8165736 8252657 + * @comment muslc dlclose is a no-op, see 8285921 + * @requires !vm.musl * @library /test/lib * @run testng AttachReturnError */ diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/dtrace/DTraceOptionsTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/dtrace/DTraceOptionsTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/dtrace/DTraceOptionsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/dtrace/DTraceOptionsTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=enabled + * @bug 8281822 + * @summary Test DTrace options are accepted on suitable builds + * @requires vm.flagless + * @requires vm.hasDTrace + * + * @library /test/lib + * @run driver DTraceOptionsTest true + */ + +/* + * @test id=disabled + * @bug 8281822 + * @summary Test DTrace options are rejected on unsuitable builds + * @requires vm.flagless + * @requires !vm.hasDTrace + * + * @library /test/lib + * @run driver DTraceOptionsTest disabled + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class DTraceOptionsTest { + public static void main(String[] args) throws Throwable { + boolean dtraceEnabled; + if (args.length > 0) { + dtraceEnabled = Boolean.parseBoolean(args[0]); + } else { + throw new IllegalArgumentException("Should provide the argument"); + } + + String[] options = { + "ExtendedDTraceProbes", + "DTraceMethodProbes", + "DTraceAllocProbes", + "DTraceMonitorProbes", + }; + + for (String opt : options) { + var pb = ProcessTools.createJavaProcessBuilder("-XX:+" + opt, "-version"); + var oa = new OutputAnalyzer(pb.start()); + if (dtraceEnabled) { + oa.shouldHaveExitValue(0); + } else { + oa.shouldNotHaveExitValue(0); + oa.shouldContain(opt + " flag is not applicable for this configuration"); + } + } + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/FieldAccessWatch.java openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/FieldAccessWatch.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/FieldAccessWatch.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/FieldAccessWatch.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ throw ex; } - if (!initWatchers(MyList.class, MyList.class.getDeclaredField("items"))) { + if (!initWatchers(MyList.class, MyList.class.getDeclaredField("items"), Thread.currentThread())) { throw new RuntimeException("Watchers initializations error"); } @@ -131,7 +131,7 @@ log(descr + ": OK"); } - private static native boolean initWatchers(Class cls, Field field); + private static native boolean initWatchers(Class cls, Field field, Thread testThread); private static native boolean startTest(TestResult results); private static native void stopTest(); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c --- openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ // valid while a test is executed static jobject testResultObject = NULL; static jclass testResultClass = NULL; +static jthread testThread = NULL; static void reportError(const char *msg, int err) { @@ -46,6 +47,7 @@ // logs the notification and updates currentTestResult static void handleNotification(JNIEnv *jni_env, + jthread thread, jmethodID method, jfieldID field, jclass field_klass, @@ -64,6 +66,10 @@ return; } + if (!(*jni_env)->IsSameObject(jni_env, thread, testThread)) { + return; // skip events from unexpected threads + } + err = (*jvmti)->GetFieldName(jvmti, field_klass, field, &name, NULL, NULL); if (err != JVMTI_ERROR_NONE) { reportError("GetFieldName failed", err); @@ -179,7 +185,7 @@ jobject object, jfieldID field) { - handleNotification(jni_env, method, field, field_klass, 0, location); + handleNotification(jni_env, thread, method, field, field_klass, 0, location); } @@ -195,7 +201,7 @@ char signature_type, jvalue new_value) { - handleNotification(jni_env, method, field, field_klass, 1, location); + handleNotification(jni_env, thread, method, field, field_klass, 1, location); if (signature_type == 'L') { jobject newObject = new_value.l; @@ -208,14 +214,15 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { jvmtiError err; - jvmtiCapabilities caps = {0}; - jvmtiEventCallbacks callbacks = {0}; + jvmtiCapabilities caps; + jvmtiEventCallbacks callbacks; jint res = (*jvm)->GetEnv(jvm, (void **) &jvmti, JVMTI_VERSION_1_1); if (res != JNI_OK || jvmti == NULL) { reportError("GetEnv failed", res); return JNI_ERR; } + memset(&caps, 0, sizeof(caps)); caps.can_generate_field_modification_events = 1; caps.can_generate_field_access_events = 1; caps.can_tag_objects = 1; @@ -225,6 +232,7 @@ return JNI_ERR; } + memset(&callbacks, 0, sizeof(callbacks)); callbacks.FieldModification = &onFieldModification; callbacks.FieldAccess = &onFieldAccess; @@ -251,7 +259,7 @@ JNIEXPORT jboolean JNICALL -Java_FieldAccessWatch_initWatchers(JNIEnv *env, jclass thisClass, jclass cls, jobject field) +Java_FieldAccessWatch_initWatchers(JNIEnv *env, jclass thisClass, jclass cls, jobject field, jthread thread) { jfieldID fieldId; jvmtiError err; @@ -275,6 +283,8 @@ return JNI_FALSE; } + testThread = (jthread)(*env)->NewGlobalRef(env, thread); + return JNI_TRUE; } diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/GetClassMethods/libOverpassMethods.cpp openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/GetClassMethods/libOverpassMethods.cpp --- openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/GetClassMethods/libOverpassMethods.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/GetClassMethods/libOverpassMethods.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * 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,7 +45,8 @@ if (options != NULL && strcmp(options, "maintain_original_method_order") == 0) { printf("Enabled capability: maintain_original_method_order\n"); - jvmtiCapabilities caps = {}; + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); caps.can_maintain_original_method_order = 1; jvmtiError err = jvmti->AddCapabilities(&caps); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp --- openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 +#include + +#include "jvmti.h" + +#define TARGET_CLASS_NAME "LTarget;" + +static jvmtiEnv *jvmti = NULL; + +static void +check_jvmti_status(JNIEnv* jni, jvmtiError err, const char* msg) { + if (err != JVMTI_ERROR_NONE) { + printf("check_jvmti_status: %s, JVMTI function returned error: %d\n", msg, err); + jni->FatalError(msg); + } +} + +void JNICALL classprepare(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass) { + char* buf; + jvmtiError err; + + err = jvmti->GetClassSignature(klass, &buf, NULL); + check_jvmti_status(jni_env, err, "classprepare: GetClassSignature error"); + + if (strncmp(buf, TARGET_CLASS_NAME, strlen(TARGET_CLASS_NAME)) == 0) { + jint nMethods; + jmethodID* methods; + int i; + + err = jvmti->GetClassMethods(klass, &nMethods, &methods); + check_jvmti_status(jni_env, err, "classprepare: GetClassMethods error"); + printf("Setting breakpoints in %s\n", buf); + fflush(stdout); + for (i = 0; i < nMethods; i++) { + err = jvmti->SetBreakpoint(methods[i], 0); + check_jvmti_status(jni_env, err, "classprepare: SetBreakpoint error"); + } + } +} + + +void JNICALL breakpoint(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location) { + // Do nothing +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { + jvmtiCapabilities capa; + jvmtiEventCallbacks cbs; + jint err; + + err = vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0); + if (err != JNI_OK) { + printf("Agent_OnLoad: GetEnv error\n"); + return JNI_ERR; + } + + memset(&capa, 0, sizeof(capa)); + capa.can_generate_breakpoint_events = 1; + capa.can_generate_single_step_events = 1; + err = jvmti->AddCapabilities(&capa); + if (err != JNI_OK) { + printf("Agent_OnLoad: AddCapabilities error\n"); + return JNI_ERR; + } + + memset(&cbs, 0, sizeof(cbs)); + cbs.ClassPrepare = classprepare; + cbs.Breakpoint = breakpoint; + err = jvmti->SetEventCallbacks(&cbs, sizeof(cbs)); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventCallbacks error\n"); + return JNI_ERR; + } + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventNotificationMode CLASS_PREPARE error\n"); + return JNI_ERR; + } + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventNotificationMode BREAKPOINT error\n"); + return JNI_ERR; + } + + return JNI_OK; +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8144992 + * @requires vm.jvmti + * @modules java.base/jdk.internal.org.objectweb.asm + * @run main/othervm/native -agentlib:TestManyBreakpoints + * -Xlog:gc+metaspace + * -Xint + * -XX:MetaspaceSize=16K -XX:MaxMetaspaceSize=64M + * TestManyBreakpoints + */ + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +public class TestManyBreakpoints { + + static final int BATCHES = 50; + static final int METHODS = 1000; + + public static void main(String[] args) throws Exception { + for (int c = 0; c < BATCHES; c++) { + System.out.println("Batch " + c); + TestClassLoader loader = new TestClassLoader(); + Class.forName("Target", true, loader); + } + } + + private static class TestClassLoader extends ClassLoader implements Opcodes { + static byte[] TARGET_BYTES = generateTarget(); + + private static byte[] generateTarget() { + ClassWriter cw = new ClassWriter(0); + + cw.visit(52, ACC_SUPER | ACC_PUBLIC, "Target", null, "java/lang/Object", null); + for (int m = 0; m < METHODS; m++) { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m" + m, "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals("Target")) { + return defineClass(name, TARGET_BYTES, 0, TARGET_BYTES.length); + } else { + return super.findClass(name); + } + } + } + +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/TEST.groups openjdk-17-17.0.4+8/test/hotspot/jtreg/TEST.groups --- openjdk-17-17.0.3+7/test/hotspot/jtreg/TEST.groups 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/TEST.groups 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -94,6 +94,9 @@ compiler/vectorapi/VectorRebracket128Test.java \ -compiler/intrinsics/string/TestStringLatin1IndexOfChar.java +hotspot_compiler_arraycopy = \ + compiler/arraycopy/stress + tier1_common = \ sanity/BasicVMTest.java \ gtest/GTestWrapper.java \ @@ -114,7 +117,9 @@ hotspot_slow_compiler = \ compiler/codegen/aes \ compiler/codecache/stress \ - compiler/gcbarriers/PreserveFPRegistersTest.java + compiler/gcbarriers/PreserveFPRegistersTest.java \ + resourcehogs/compiler \ + :hotspot_compiler_arraycopy tier1_compiler_1 = \ compiler/arraycopy/ \ @@ -131,6 +136,7 @@ -compiler/c2/Test6792161.java \ -compiler/c2/Test6603011.java \ -compiler/c2/Test6912517.java \ + -:hotspot_slow_compiler tier1_compiler_2 = \ compiler/classUnloading/ \ diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/TEST.ROOT openjdk-17-17.0.4+8/test/hotspot/jtreg/TEST.ROOT --- openjdk-17-17.0.3+7/test/hotspot/jtreg/TEST.ROOT 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/TEST.ROOT 2022-07-14 08:05:38.000000000 +0000 @@ -63,6 +63,7 @@ vm.debug \ vm.hasSA \ vm.hasJFR \ + vm.hasDTrace \ vm.rtm.cpu \ vm.rtm.compiler \ vm.cds \ diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * 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,12 +23,11 @@ package nsk.share.gc; -import java.io.*; -import java.util.*; - import nsk.share.test.ExecutionController; import nsk.share.test.LocalRandom; +import java.io.PrintStream; + /** * NonbranchyTree defines a tree structure. Each node of the tree * always has one son. A node may have the second son with probability @@ -38,11 +37,9 @@ /** Minimal size of each node (in bytes) */ public final static int MIN_NODE_SIZE = 20; - private Node root; - private int numberOfNodes; - private float branchiness; - private int size; - private ExecutionController controller; + private final Node root; + private final float branchiness; + private final ExecutionController controller; /** * Creates a new tree with number of nodes not more than @@ -62,36 +59,26 @@ */ public NonbranchyTree(int numberOfNodes, float branchiness, int size) { this(numberOfNodes, branchiness, size, null); - initTree(); } public NonbranchyTree(int numberOfNodes, float branchiness, int size, ExecutionController controller) { - this.numberOfNodes = numberOfNodes; - this.branchiness = branchiness; - this.size = size; - this.controller = controller; - initTree(); - } - - private void initTree() { if (numberOfNodes < 1) { throw new IllegalArgumentException("Illegal number of nodes: " - + numberOfNodes + ", must be at " - + "least 1."); + + numberOfNodes + ", must be at least 1."); } - if ( (branchiness >= 1) || (branchiness <= 0) ) { + if ((branchiness >= 1) || (branchiness <= 0)) { throw new IllegalArgumentException("Illegal value of branchiness: " - + numberOfNodes + ", must be at " - + "greater than 0 and less than " - + " 1."); + + branchiness + ", must be greater than 0 and less than 1."); } if (size < 1) { throw new IllegalArgumentException("Illegal size of nodes: " - + size + ", must be at least 1."); + + size + ", must be at least 1."); } // ensure that LocalRandom is loaded and has enough memory LocalRandom.nextBoolean(); - root = createTree(numberOfNodes, size); + this.branchiness = branchiness; + this.controller = controller; + this.root = createTree(numberOfNodes, size); } // Create a new tree with specified number of nodes and size of each node diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/agent_tools.cpp 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,34 +138,25 @@ return jvmti_env; } -/* ============================================================================= */ -static void set_agent_thread_state(thread_state_t value) { - rawMonitorEnter(jvmti_env, agent_data.monitor); - agent_data.thread_state = value; - rawMonitorNotify(jvmti_env, agent_data.monitor); - rawMonitorExit(jvmti_env, agent_data.monitor); -} - /** Wrapper for user agent thread. */ static void JNICALL agentThreadWrapper(jvmtiEnv* jvmti_env, JNIEnv* agentJNI, void* arg) { jni_env = agentJNI; - /* run user agent proc */ - { - set_agent_thread_state(RUNNABLE); + rawMonitorEnter(jvmti_env, agent_data.monitor); + agent_data.thread_state = RUNNABLE; + rawMonitorNotify(jvmti_env, agent_data.monitor); + rawMonitorExit(jvmti_env, agent_data.monitor); - NSK_TRACE((*agentThreadProc)(jvmti_env, agentJNI, agentThreadArg)); + NSK_TRACE((*agentThreadProc)(jvmti_env, agentJNI, agentThreadArg)); - set_agent_thread_state(TERMINATED); - } + rawMonitorEnter(jvmti_env, agent_data.monitor); + agent_data.thread_state = TERMINATED; + agentJNI->DeleteGlobalRef(agentThread); + agentThread = NULL; + rawMonitorNotify(jvmti_env, agent_data.monitor); + rawMonitorExit(jvmti_env, agent_data.monitor); - /* finalize agent thread */ - { - /* gelete global ref for agent thread */ - agentJNI->DeleteGlobalRef(agentThread); - agentThread = NULL; - } } /** Start wrapper for user agent thread. */ diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/BTreeTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/BTreeTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/BTreeTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/BTreeTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -59,7 +59,7 @@ } try { // Load FatsInfo with URLClassLoader btree.jar & fats.jar should not - // present in classpath + // be present in classpath Class info; if (useFats) { info = createJarLoader().loadClass(PACKAGE_PREFIX + "FatsInfo"); @@ -76,7 +76,7 @@ } if (level >= height) { - throw new Failure("Icorrect level : " + level + " .Should be less then " + height); + throw new Failure("Incorrect level : " + level + " should be less than " + height); } // generate names for all nodes at the given level: diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/GenClassesBuilder.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/GenClassesBuilder.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/GenClassesBuilder.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/GenClassesBuilder.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ moveJavaFiles(genSrcDir, prefix); JDKToolLauncher javac = JDKToolLauncher.create("javac") + .addToolArg("-J-Xmx1G") .addToolArg("-d") .addToolArg(classesDir.toString()) .addToolArg("-cp") diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/SysDictTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/SysDictTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/SysDictTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/nsk/sysdict/share/SysDictTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ if (args[i].equals("-useSingleLoader")) { this.useSingleLoader = false; } - // jar path is in useal classpath format + // jar path is in usual classpath format if (args[i].equals("-jarpath")) { String[] files = args[i + 1].split(File.pathSeparator); jars = new URL[files.length]; @@ -148,11 +148,8 @@ // set name into public variable just to be sure // that class is loaded tmp = clz.getName(); - } catch (ClassNotFoundException cnfe) { - throw new TestFailure(cnfe); - } catch (OutOfMemoryError oome) { - // just ignore - // we do not check memory leaks in PermGen in this tests + } catch (OutOfMemoryError | ClassNotFoundException | NoClassDefFoundError e) { + // just ignore, note that CNFE and NCDFE can be caused by OOM exceptions. } catch (StackOverflowError soe) { // just ignore, chains could be too large // StackOverflowError could be in some sparcs @@ -164,6 +161,7 @@ } } + @Override protected Runnable createRunnable(int i) { currentClassLoaders = createClassLoadersInternal(); diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/func/findByName/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/func/findByName/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/func/findByName/Test.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/func/findByName/Test.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. - * 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 - * @modules java.base/jdk.internal.misc - * - * @summary converted from VM Testbase vm/mlvm/anonloader/func/findByName. - * VM Testbase keywords: [feature_mlvm] - * VM Testbase readme: - * DESCRIPTION - * Try to find a class loaded as a hidden class through the VM system dictionary - * (using Class.forName()). It is an error when the class can be found in this way. - * - * @library /vmTestbase - * /test/lib - * - * @comment build test class and indify classes - * @build vm.mlvm.anonloader.func.findByName.Test - * @run driver vm.mlvm.share.IndifiedClassesBuilder - * - * @run main/othervm vm.mlvm.anonloader.func.findByName.Test - */ - -package vm.mlvm.anonloader.func.findByName; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; - -import vm.mlvm.anonloader.share.AnonkTestee01; -import vm.mlvm.share.MlvmTest; -import vm.share.FileUtils; - -public class Test extends MlvmTest { - private static final Class PARENT = AnonkTestee01.class; - - public boolean run() throws Exception { - try { - byte[] classBytes = FileUtils.readClass(PARENT.getName()); - Lookup lookup = MethodHandles.lookup(); - Lookup ank_lookup = MethodHandles.privateLookupIn(PARENT, lookup); - Class c = ank_lookup.defineHiddenClass(classBytes, true).lookupClass(); - getLog().display("Hidden class name: " + c.getName()); - Class.forName(c.getName()).newInstance(); - return false; - } catch ( ClassNotFoundException e ) { - return true; - } - } - - public static void main(String[] args) { MlvmTest.launch(args); } -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/AnonkTestee01.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/AnonkTestee01.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/AnonkTestee01.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/AnonkTestee01.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2010, 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. - */ - -package vm.mlvm.anonloader.share; - -import vm.mlvm.share.Env; - -public class AnonkTestee01 { - public final static String muzzy = "BIG \uFFFF\u0000\uFFFE\uFEFF MUZZY"; - public final static String - theDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrum - = String.format("%65500c%X", 'c', Env.getRNG().nextLong()); - - public final String beatingTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrum() { - return theDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrum; - } - - public final String toString() { - return "Something that looks like " + super.toString(); - } - - @Override - public int hashCode() { - throw new RuntimeException("Making fun of errors"); - } -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/AnonkTestee02.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/AnonkTestee02.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/AnonkTestee02.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/AnonkTestee02.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2010, 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. - */ - -package vm.mlvm.anonloader.share; - -public class AnonkTestee02 extends AnonkTestee01 { - public AnonkTestee02() {} -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/StressClassLoadingTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/StressClassLoadingTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/StressClassLoadingTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/share/StressClassLoadingTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. - * 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 vm.mlvm.anonloader.share; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; - -import java.io.File; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import nsk.share.test.Stresser; -import vm.share.options.Option; -import vm.share.options.OptionSupport; -import vm.share.options.IgnoreUnknownArgumentsHandler; -import vm.mlvm.share.Env; -import vm.mlvm.share.MlvmTest; -import vm.mlvm.share.CustomClassLoaders; -import vm.share.FileUtils; -import vm.share.UnsafeAccess; - -/** - * Does stress-testing of class loading subsystem. - * This class should be subclassed by the tests - * to provide test class data. - * - *

    StressClassLoadingTest performs a number of iterations - * (the default value is 100 000). - * Each iteration gets class bytes from the subclass - * and loads it into JVM using either: - *

      - *
    • a custom {@link java.lang.ClassLoader} implementation or - *
    • {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} call. - *
    - * - *

    Loading is done in a separate thread. If this thread is stuck, - * it is killed after some timeout (default is 10 seconds, please see - * -parseTimeout option). The class file is saved as hangXX.class, where XX - * starts at 00 and is increased on every hangup. - * A prefix can be added to the file name using {@link #setFileNamePrefix} - * - *

    The test fails, if there were hangups. - * - *

    By default, before loading class, the bytes are - * saved to {@code _AnonkTestee01.class} file in the current directory. - * If JVM crashes, the bytecodes can be analysed. - * Class saving is controlled by -saveClassFile option. - * A prefix can be added to the file name using {@link #setFileNamePrefix} - * function. - */ -public abstract class StressClassLoadingTest extends MlvmTest { - private static final String RESCUE_FILE_NAME = "_AnonkTestee01.class"; - private static final String HUNG_CLASS_FILE_NAME = "hang.class"; - - @Option(name = "iterations", default_value = "100000", - description = "How many times generate a class and parse it") - private static int iterations; - - @Option(name = "saveClassFile", default_value = "true", - description = "Save generated class file before loading." - + " Useful when VM crashes on loading") - private static boolean saveClassFile; - - @Option(name = "parseTimeout", default_value = "10000", - description = "Timeout in millisectionds to detect hung parser" - + " thread. The parser thread is killed after the timeout") - private static int parseTimeout; - - @Option(name = "hiddenLoad", default_value = "false", - description = "An option for adhoc experiments: load class as a hidden class.") - private static boolean hiddenLoad; - - private String fileNamePrefix = ""; - - private final static AtomicBoolean classFileMessagePrinted - = new AtomicBoolean(false); - - /** - * Sets prefix for names of the files, created by test: - * _AnonkTestee01.class and hangXX.class. - * - * @param p a prefix to add before file name. - * @throws java.lang.NullPointerException if p is null - */ - public void setFileNamePrefix(String p) { - Objects.requireNonNull(p); - fileNamePrefix = p; - } - - static volatile boolean optionsSetup = false; - public static void setupOptions(Object instance) { - if (!optionsSetup) { - synchronized (StressClassLoadingTest.class) { - if (!optionsSetup) { - OptionSupport.setup(instance, Env.getArgParser().getRawArguments(), new IgnoreUnknownArgumentsHandler()); - optionsSetup = true; - - Env.traceNormal("StressClassLoadingTest options: iterations: " + iterations); - Env.traceNormal("StressClassLoadingTest options: hiddenLoad: " + hiddenLoad); - Env.traceNormal("StressClassLoadingTest options: parseTimeout: " + parseTimeout); - Env.traceNormal("StressClassLoadingTest options: saveClassFile: " + saveClassFile); - } - } - } - } - - public boolean run() throws Exception { - setupOptions(this); - - Stresser stresser = createStresser(); - stresser.start(iterations); - - while (stresser.continueExecution()) { - stresser.iteration(); - - byte[] classBytes = generateClassBytes(); - Class hostClass = getHostClass(); - String className = hostClass.getName(); - File rescueFile = new File(String.format("%s_%d_%s", - fileNamePrefix, stresser.getIteration(), RESCUE_FILE_NAME)); - if (saveClassFile) { - // Write out the class file being loaded. It's useful - // to have if the JVM crashes. - FileUtils.writeBytesToFile(rescueFile, classBytes); - if (classFileMessagePrinted.compareAndSet(false, true)) { - Env.traceImportant("If the JVM crashes then " - + "the class file causing the crash is saved as *_*_" - + RESCUE_FILE_NAME); - } - } - - Thread parserThread = new Thread() { - public void run() { - try { - Class c; - if (hiddenLoad) { - Lookup lookup = MethodHandles.lookup(); - c = lookup.defineHiddenClass(classBytes, true).lookupClass(); - - } else { - c = CustomClassLoaders.makeClassBytesLoader(classBytes, className) - .loadClass(className); - } - UnsafeAccess.unsafe.ensureClassInitialized(c); - } catch (Throwable e) { - Env.traceVerbose(e, "parser caught exception"); - } - } - }; - - parserThread.start(); - parserThread.join(parseTimeout); - - if (parserThread.isAlive()) { - Env.traceImportant("parser thread may be hung!"); - StackTraceElement[] stack = parserThread.getStackTrace(); - Env.traceImportant("parser thread stack len: " + stack.length); - Env.traceImportant(parserThread + " stack trace:"); - for (int i = 0; i < stack.length; ++i) { - Env.traceImportant(parserThread + "\tat " + stack[i]); - } - - Path savedClassPath = Paths.get(fileNamePrefix + HUNG_CLASS_FILE_NAME); - - if (saveClassFile) { - Files.move(rescueFile.toPath(), savedClassPath); - Env.traceImportant("There was a possible hangup during parsing." - + " The class file, which produced the possible hangup, was saved as " - + fileNamePrefix + HUNG_CLASS_FILE_NAME - + "... in the test directory. You may want to analyse it " - + "if this test times out."); - } - - parserThread.join(); // Wait until either thread finishes or test times out. - if (saveClassFile) { - savedClassPath.toFile().delete(); - } - } else if (saveClassFile) { - rescueFile.delete(); - } - } - - stresser.finish(); - return true; - } - - /** - * Generated class bytes. The method is called for each iteration. - * - * @return Byte array with the generated class - */ - protected abstract byte[] generateClassBytes(); - - /** - * Returns a host class for the generated class. - * - * @return A host class that for the generated class - */ - protected abstract Class getHostClass(); -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/byteMutation/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/byteMutation/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/byteMutation/Test.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/byteMutation/Test.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. - * 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 - * @key randomness - * @modules java.base/jdk.internal.misc - * - * @summary converted from VM Testbase vm/mlvm/anonloader/stress/byteMutation. - * VM Testbase keywords: [feature_mlvm, nonconcurrent] - * - * @library /vmTestbase - * /test/lib - * - * @comment build test class and indify classes - * @build vm.mlvm.anonloader.stress.byteMutation.Test - * @run driver vm.mlvm.share.IndifiedClassesBuilder - * - * @run main/othervm vm.mlvm.anonloader.stress.byteMutation.Test -stressIterationsFactor 100000 - */ - -package vm.mlvm.anonloader.stress.byteMutation; - -import vm.mlvm.anonloader.share.AnonkTestee01; -import vm.mlvm.anonloader.share.StressClassLoadingTest; -import vm.share.FileUtils; -import vm.share.options.Option; - -/** - * The test does the following in a cycle: - * - *

      - *
    1. Takes bytes from a valid class file - *
    2. Sets 1 to 5 bytes in random positions to random values - *
    3. Tries to load such class using: - *
        - *
      • a custom class loader, - *
      • {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} - * when {@code -hiddenLoad true} option is passed to the test. - *
      - *
    - * - *

    In most cases the resulting class file is invalid and rejected by - * the VM verifier. But this test tries to find pathological cases, such - * as infinite loops during verification or VM crashes. - * - */ -public class Test extends StressClassLoadingTest { - private final static Class HOST_CLASS = AnonkTestee01.class; - private final byte[] testeeBytes; - @Option(name = "mutationCount", default_value = "3", - description = "How many bytes to mutate in a class") - private int mutationCount = 3; - - /** - * Constructs the test. - * @throws Exception if there are any errors when - * reading {@link vm.mlvm.anonloader.share.AnonkTestee01} class bytecodes. - */ - public Test() throws Exception { - this.testeeBytes = FileUtils.readClass(AnonkTestee01.class.getName()); - } - - /** - * Returns {@link vm.mlvm.anonloader.share.AnonkTestee01} class to the - * parent. - * @return {@link vm.mlvm.anonloader.share.AnonkTestee01} class. - */ - @Override - protected Class getHostClass() { - return HOST_CLASS; - } - - /** - * Takes {@link vm.mlvm.anonloader.share.AnonkTestee01} class bytecodes - * and modifies mutationCount bytes setting them to random values. - * @return {@link vm.mlvm.anonloader.share.AnonkTestee01} class bytecodes with modified bytes. - */ - @Override - protected byte[] generateClassBytes() { - // TODO: there is non-zero probability that generated bytecode will be - // valid, so it should be a subject of fuzzing mechanism - byte[] alteredBytes = testeeBytes.clone(); - for (int j = 0; j < mutationCount; ++j) { - alteredBytes[getRNG().nextInt(alteredBytes.length)] = (byte) getRNG().nextInt(256); - } - return alteredBytes; - } - - /** - * Runs the test. - * @param args Test arguments. - */ - public static void main(String[] args) { - StressClassLoadingTest.launch(args); - } -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/byteMutation/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/byteMutation/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/byteMutation/TEST.properties 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/byteMutation/TEST.properties 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# -# Copyright (c) 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. -# - -exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/heap/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/heap/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/heap/Test.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/heap/Test.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. - * 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 - * @key randomness - * @modules java.base/jdk.internal.misc - * - * @summary converted from VM Testbase vm/mlvm/anonloader/stress/oome/heap. - * VM Testbase keywords: [feature_mlvm, nonconcurrent] - * - * @library /vmTestbase - * /test/lib - * - * @comment build test class and indify classes - * @build vm.mlvm.anonloader.stress.oome.heap.Test - * @run driver vm.mlvm.share.IndifiedClassesBuilder - * - * @run main/othervm -XX:-UseGCOverheadLimit -Xmx128m vm.mlvm.anonloader.stress.oome.heap.Test - */ - -package vm.mlvm.anonloader.stress.oome.heap; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.util.List; -import java.io.IOException; - -import vm.mlvm.anonloader.share.AnonkTestee01; -import vm.mlvm.share.MlvmOOMTest; -import vm.mlvm.share.MlvmTestExecutor; -import vm.mlvm.share.Env; -import vm.share.FileUtils; - -/** - * This test loads a class using defineHiddenClass, creates instances - * of that class and stores them, expecting Heap OOME. - * - */ - -public class Test extends MlvmOOMTest { - @Override - protected void checkOOME(OutOfMemoryError oome) { - String message = oome.getMessage(); - if (!"Java heap space".equals(message)) { - throw new RuntimeException("TEST FAIL : wrong OOME", oome); - } - } - @Override - protected void eatMemory(List list) { - byte[] classBytes = null; - try { - classBytes = FileUtils.readClass(AnonkTestee01.class.getName()); - } catch (IOException e) { - Env.throwAsUncheckedException(e); - } - try { - while (true) { - Lookup lookup = MethodHandles.lookup(); - Lookup ank_lookup = MethodHandles.privateLookupIn(AnonkTestee01.class, lookup); - Class c = ank_lookup.defineHiddenClass(classBytes, true).lookupClass(); - list.add(c.newInstance()); - } - } catch (InstantiationException | IllegalAccessException e) { - Env.throwAsUncheckedException(e); - } - } - - public static void main(String[] args) { - MlvmTestExecutor.launch(args); - } -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/heap/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/heap/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/heap/TEST.properties 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/heap/TEST.properties 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# -# Copyright (c) 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. -# - -exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/metaspace/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/metaspace/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/metaspace/Test.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/metaspace/Test.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. - * 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 - * @modules java.base/jdk.internal.misc - * - * @summary converted from VM Testbase vm/mlvm/anonloader/stress/oome/metaspace. - * VM Testbase keywords: [feature_mlvm, nonconcurrent] - * - * @library /vmTestbase - * /test/lib - * - * @comment build test class and indify classes - * @build vm.mlvm.anonloader.stress.oome.metaspace.Test - * @run driver vm.mlvm.share.IndifiedClassesBuilder - * - * @run main/othervm -XX:MaxRAMPercentage=25 -XX:-UseGCOverheadLimit -XX:MetaspaceSize=10m - * -XX:MaxMetaspaceSize=20m vm.mlvm.anonloader.stress.oome.metaspace.Test - */ - -package vm.mlvm.anonloader.stress.oome.metaspace; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.util.List; -import java.io.IOException; - -import vm.mlvm.anonloader.share.AnonkTestee01; -import vm.mlvm.share.MlvmOOMTest; -import vm.mlvm.share.MlvmTestExecutor; -import vm.mlvm.share.Env; -import vm.share.FileUtils; - -/** - * This test loads classes using defineHiddenClass and stores them, - * expecting Metaspace OOME. - * - */ -public class Test extends MlvmOOMTest { - @Override - protected void checkOOME(OutOfMemoryError oome) { - String message = oome.getMessage(); - if (!"Metaspace".equals(message) && !"Compressed class space".equals(message)) { - throw new RuntimeException("TEST FAIL : wrong OOME", oome); - } - } - - @Override - protected void eatMemory(List list) { - byte[] classBytes = null; - try { - classBytes = FileUtils.readClass(AnonkTestee01.class.getName()); - } catch (IOException e) { - Env.throwAsUncheckedException(e); - } - try { - while (true) { - Lookup lookup = MethodHandles.lookup(); - Lookup ank_lookup = MethodHandles.privateLookupIn(AnonkTestee01.class, lookup); - Class c = ank_lookup.defineHiddenClass(classBytes, true).lookupClass(); - list.add(c.newInstance()); - } - } catch (InstantiationException | IllegalAccessException e) { - Env.throwAsUncheckedException(e); - } - } - - public static void main(String[] args) { - MlvmTestExecutor.launch(args); - } -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/metaspace/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/metaspace/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/metaspace/TEST.properties 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/oome/metaspace/TEST.properties 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# -# Copyright (c) 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. -# - -exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/parallelLoad/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/parallelLoad/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/parallelLoad/Test.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/parallelLoad/Test.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. - * 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 - * @modules java.base/jdk.internal.misc - * - * @summary converted from VM Testbase vm/mlvm/anonloader/stress/parallelLoad. - * VM Testbase keywords: [feature_mlvm, nonconcurrent] - * - * @library /vmTestbase - * /test/lib - * - * @comment build test class and indify classes - * @build vm.mlvm.anonloader.stress.parallelLoad.Test - * @run driver vm.mlvm.share.IndifiedClassesBuilder - * - * @run main/othervm - * -Xverify:all - * vm.mlvm.anonloader.stress.parallelLoad.Test - * -threadsPerCpu 4 - * -threadsExtra 20 - * -parseTimeout 0 - * -hiddenLoad true - */ - -package vm.mlvm.anonloader.stress.parallelLoad; - -import vm.mlvm.anonloader.share.StressClassLoadingTest; -import vm.mlvm.anonloader.share.AnonkTestee01; -import vm.mlvm.share.MlvmTestExecutor; -import vm.mlvm.share.MultiThreadedTest; -import vm.share.FileUtils; - -/** - * Verifies that loading classes in parallel from several threads using - * {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} - * does not produce exceptions and crashes. - * - */ -public class Test extends MultiThreadedTest { - private static final Class HOST_CLASS = AnonkTestee01.class; - private static final String NAME_PREFIX = "thread%03d"; - - private final byte[] classBytes; - - private static class SubTest extends StressClassLoadingTest { - private final byte[] classBytes; - - public SubTest(byte[] classBytes) { - this.classBytes = classBytes; - } - - @Override - protected Class getHostClass() { - return HOST_CLASS; - } - - @Override - protected byte[] generateClassBytes() { - return classBytes; - } - } - - public Test() throws Exception { - classBytes = FileUtils.readClass(HOST_CLASS.getName()); - } - - /** - * Constructs a sub-test class and runs it. The sub-test class loads - * {@link vm.mlvm.anonloader.share.AnonkTestee01} class bytecodes - * using {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} - * @param numThread Number of the thread - * @throws Exception if there any exceptions thrown in the sub-test - */ - @Override - protected boolean runThread(int numThread) throws Exception { - SubTest subTest = new SubTest(classBytes); - subTest.setFileNamePrefix(String.format(NAME_PREFIX, numThread)); - return subTest.run(); - } - - /** - * Runs the test. - * @param args Test arguments. - */ - public static void main(String[] args) { - MlvmTestExecutor.launch(args); - } -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/parallelLoad/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/parallelLoad/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/parallelLoad/TEST.properties 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/parallelLoad/TEST.properties 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# -# Copyright (c) 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. -# - -exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/randomBytecodes/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/randomBytecodes/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/randomBytecodes/Test.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/randomBytecodes/Test.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. - * 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 - * @key randomness - * @modules java.base/jdk.internal.misc - * - * @summary converted from VM Testbase vm/mlvm/anonloader/stress/randomBytecodes. - * VM Testbase keywords: [feature_mlvm, nonconcurrent] - * - * @library /vmTestbase - * /test/lib - * - * @comment build test class and indify classes - * @build vm.mlvm.anonloader.stress.randomBytecodes.Test - * @run driver vm.mlvm.share.IndifiedClassesBuilder - * - * @run main/othervm vm.mlvm.anonloader.stress.randomBytecodes.Test -stressIterationsFactor 100000 - */ - -package vm.mlvm.anonloader.stress.randomBytecodes; - -import java.util.Arrays; -import vm.mlvm.anonloader.share.StressClassLoadingTest; - -/** - * The test does the following in a cycle: - *
      - *
    1. Creates a class bytecodes that has a valid 12-byte header - * and has totally random bytes after the header - *
    2. Tries to load such class using: - *
        - *
      • a custom class loader, or - *
      • {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} - * when {@code -hiddenLoad true} is set. - *
      - *
    - * - *

    In most cases the resulting class file is invalid and rejected by - * the VM verifier. But this test is looking for pathological cases - * such as infinite loops in the verifier or VM crashes. - * - */ -public class Test extends StressClassLoadingTest { - private static final Class HOST_CLASS = Test.class; - private static final int MAX_SIZE = 0xFFF7; - private static final byte[] CLASS_HEADER = new byte[] { - (byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, - 0x00, 0x00, 0x00, 0x32 - }; - - /** - * Returns {@link vm.mlvm.anonloader.share.AnonkTestee01} class to the - * parent. - * @return {@link vm.mlvm.anonloader.share.AnonkTestee01} class. - */ - @Override - protected Class getHostClass() { - return HOST_CLASS; - } - - /** - * Generates a class with valid header (magic and version fields) and - * random bytes after the header. - *

    Class size is random ([8..65527]). - * Byte values are limited to [0..11] range in order to increase - * possiblity that the random class passes the initial (dead-on-arrival) - * stages of the verifier and is rejected - * in more interesting ones, like method bytecode verification. - * Class version is 52. - * - * @return Class with valid Java header (8 bytes) and totally random bytes - * after the header - */ - @Override - protected byte[] generateClassBytes() { - final byte[] classBytes = Arrays.copyOf(CLASS_HEADER, - CLASS_HEADER.length + getRNG().nextInt(MAX_SIZE)); - for (int j = CLASS_HEADER.length; j < classBytes.length; j++) { - classBytes[j] = (byte) getRNG().nextInt(12); - } - - return classBytes; - } - - /** - * Runs the test. - * @param args Test arguments. - */ - public static void main(String[] args) { - StressClassLoadingTest.launch(args); - } -} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/randomBytecodes/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/randomBytecodes/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/randomBytecodes/TEST.properties 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/stress/randomBytecodes/TEST.properties 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# -# Copyright (c) 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. -# - -exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/func/findByName/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/func/findByName/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/func/findByName/Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/func/findByName/Test.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 + * @modules java.base/jdk.internal.misc + * + * @summary converted from VM Testbase vm/mlvm/anonloader/func/findByName. + * VM Testbase keywords: [feature_mlvm] + * VM Testbase readme: + * DESCRIPTION + * Try to find a class loaded as a hidden class through the VM system dictionary + * (using Class.forName()). It is an error when the class can be found in this way. + * + * @library /vmTestbase + * /test/lib + * + * @comment build test class and indify classes + * @build vm.mlvm.hiddenloader.func.findByName.Test + * @run driver vm.mlvm.share.IndifiedClassesBuilder + * + * @run main/othervm vm.mlvm.hiddenloader.func.findByName.Test + */ + +package vm.mlvm.hiddenloader.func.findByName; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; + +import vm.mlvm.hiddenloader.share.HiddenkTestee01; +import vm.mlvm.share.MlvmTest; +import vm.share.FileUtils; + +public class Test extends MlvmTest { + private static final Class PARENT = HiddenkTestee01.class; + + public boolean run() throws Exception { + try { + byte[] classBytes = FileUtils.readClass(PARENT.getName()); + Lookup lookup = MethodHandles.lookup(); + Lookup ank_lookup = MethodHandles.privateLookupIn(PARENT, lookup); + Class c = ank_lookup.defineHiddenClass(classBytes, true).lookupClass(); + getLog().display("Hidden class name: " + c.getName()); + Class.forName(c.getName()).newInstance(); + return false; + } catch ( ClassNotFoundException e ) { + return true; + } + } + + public static void main(String[] args) { MlvmTest.launch(args); } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/HiddenkTestee01.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/HiddenkTestee01.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/HiddenkTestee01.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/HiddenkTestee01.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010, 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. + */ + +package vm.mlvm.hiddenloader.share; + +import vm.mlvm.share.Env; + +public class HiddenkTestee01 { + public final static String muzzy = "BIG \uFFFF\u0000\uFFFE\uFEFF MUZZY"; + public final static String + theDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrum + = String.format("%65500c%X", 'c', Env.getRNG().nextLong()); + + public final String beatingTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrum() { + return theDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrumIsTheDrum; + } + + public final String toString() { + return "Something that looks like " + super.toString(); + } + + @Override + public int hashCode() { + throw new RuntimeException("Making fun of errors"); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/HiddenkTestee02.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/HiddenkTestee02.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/HiddenkTestee02.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/HiddenkTestee02.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010, 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. + */ + +package vm.mlvm.hiddenloader.share; + +public class HiddenkTestee02 extends HiddenkTestee01 { + public HiddenkTestee02() {} +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/StressClassLoadingTest.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/StressClassLoadingTest.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/StressClassLoadingTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/share/StressClassLoadingTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 vm.mlvm.hiddenloader.share; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; + +import java.io.File; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import nsk.share.test.Stresser; +import vm.share.options.Option; +import vm.share.options.OptionSupport; +import vm.share.options.IgnoreUnknownArgumentsHandler; +import vm.mlvm.share.Env; +import vm.mlvm.share.MlvmTest; +import vm.mlvm.share.CustomClassLoaders; +import vm.share.FileUtils; +import vm.share.UnsafeAccess; + +/** + * Does stress-testing of class loading subsystem. + * This class should be subclassed by the tests + * to provide test class data. + * + *

    StressClassLoadingTest performs a number of iterations + * (the default value is 100 000). + * Each iteration gets class bytes from the subclass + * and loads it into JVM using either: + *

      + *
    • a custom {@link java.lang.ClassLoader} implementation or + *
    • {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} call. + *
    + * + *

    Loading is done in a separate thread. If this thread is stuck, + * it is killed after some timeout (default is 10 seconds, please see + * -parseTimeout option). The class file is saved as hangXX.class, where XX + * starts at 00 and is increased on every hangup. + * A prefix can be added to the file name using {@link #setFileNamePrefix} + * + *

    The test fails, if there were hangups. + * + *

    By default, before loading class, the bytes are + * saved to {@code _HiddenkTestee01.class} file in the current directory. + * If JVM crashes, the bytecodes can be analysed. + * Class saving is controlled by -saveClassFile option. + * A prefix can be added to the file name using {@link #setFileNamePrefix} + * function. + */ +public abstract class StressClassLoadingTest extends MlvmTest { + private static final String RESCUE_FILE_NAME = "_HiddenkTestee01.class"; + private static final String HUNG_CLASS_FILE_NAME = "hang.class"; + + @Option(name = "iterations", default_value = "100000", + description = "How many times generate a class and parse it") + private static int iterations; + + @Option(name = "saveClassFile", default_value = "true", + description = "Save generated class file before loading." + + " Useful when VM crashes on loading") + private static boolean saveClassFile; + + @Option(name = "parseTimeout", default_value = "10000", + description = "Timeout in millisectionds to detect hung parser" + + " thread. The parser thread is killed after the timeout") + private static int parseTimeout; + + @Option(name = "hiddenLoad", default_value = "false", + description = "An option for adhoc experiments: load class as a hidden class.") + private static boolean hiddenLoad; + + private String fileNamePrefix = ""; + + private final static AtomicBoolean classFileMessagePrinted + = new AtomicBoolean(false); + + /** + * Sets prefix for names of the files, created by test: + * _HiddenkTestee01.class and hangXX.class. + * + * @param p a prefix to add before file name. + * @throws java.lang.NullPointerException if p is null + */ + public void setFileNamePrefix(String p) { + Objects.requireNonNull(p); + fileNamePrefix = p; + } + + static volatile boolean optionsSetup = false; + public static void setupOptions(Object instance) { + if (!optionsSetup) { + synchronized (StressClassLoadingTest.class) { + if (!optionsSetup) { + OptionSupport.setup(instance, Env.getArgParser().getRawArguments(), new IgnoreUnknownArgumentsHandler()); + optionsSetup = true; + + Env.traceNormal("StressClassLoadingTest options: iterations: " + iterations); + Env.traceNormal("StressClassLoadingTest options: hiddenLoad: " + hiddenLoad); + Env.traceNormal("StressClassLoadingTest options: parseTimeout: " + parseTimeout); + Env.traceNormal("StressClassLoadingTest options: saveClassFile: " + saveClassFile); + } + } + } + } + + public boolean run() throws Exception { + setupOptions(this); + + Stresser stresser = createStresser(); + stresser.start(iterations); + + while (stresser.continueExecution()) { + stresser.iteration(); + + byte[] classBytes = generateClassBytes(); + Class hostClass = getHostClass(); + String className = hostClass.getName(); + File rescueFile = new File(String.format("%s_%d_%s", + fileNamePrefix, stresser.getIteration(), RESCUE_FILE_NAME)); + if (saveClassFile) { + // Write out the class file being loaded. It's useful + // to have if the JVM crashes. + FileUtils.writeBytesToFile(rescueFile, classBytes); + if (classFileMessagePrinted.compareAndSet(false, true)) { + Env.traceImportant("If the JVM crashes then " + + "the class file causing the crash is saved as *_*_" + + RESCUE_FILE_NAME); + } + } + + Thread parserThread = new Thread() { + public void run() { + try { + Class c; + if (hiddenLoad) { + Lookup lookup = MethodHandles.lookup(); + c = lookup.defineHiddenClass(classBytes, true).lookupClass(); + + } else { + c = CustomClassLoaders.makeClassBytesLoader(classBytes, className) + .loadClass(className); + } + UnsafeAccess.unsafe.ensureClassInitialized(c); + } catch (Throwable e) { + Env.traceVerbose(e, "parser caught exception"); + } + } + }; + + parserThread.start(); + parserThread.join(parseTimeout); + + if (parserThread.isAlive()) { + Env.traceImportant("parser thread may be hung!"); + StackTraceElement[] stack = parserThread.getStackTrace(); + Env.traceImportant("parser thread stack len: " + stack.length); + Env.traceImportant(parserThread + " stack trace:"); + for (int i = 0; i < stack.length; ++i) { + Env.traceImportant(parserThread + "\tat " + stack[i]); + } + + Path savedClassPath = Paths.get(fileNamePrefix + HUNG_CLASS_FILE_NAME); + + if (saveClassFile) { + Files.move(rescueFile.toPath(), savedClassPath); + Env.traceImportant("There was a possible hangup during parsing." + + " The class file, which produced the possible hangup, was saved as " + + fileNamePrefix + HUNG_CLASS_FILE_NAME + + "... in the test directory. You may want to analyse it " + + "if this test times out."); + } + + parserThread.join(); // Wait until either thread finishes or test times out. + if (saveClassFile) { + savedClassPath.toFile().delete(); + } + } else if (saveClassFile) { + rescueFile.delete(); + } + } + + stresser.finish(); + return true; + } + + /** + * Generated class bytes. The method is called for each iteration. + * + * @return Byte array with the generated class + */ + protected abstract byte[] generateClassBytes(); + + /** + * Returns a host class for the generated class. + * + * @return A host class that for the generated class + */ + protected abstract Class getHostClass(); +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/byteMutation/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/byteMutation/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/byteMutation/Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/byteMutation/Test.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 + * @key randomness + * @modules java.base/jdk.internal.misc + * + * @summary converted from VM Testbase vm/mlvm/hiddenloader/stress/byteMutation. + * VM Testbase keywords: [feature_mlvm, nonconcurrent] + * + * @library /vmTestbase + * /test/lib + * + * @comment build test class and indify classes + * @build vm.mlvm.hiddenloader.stress.byteMutation.Test + * @run driver vm.mlvm.share.IndifiedClassesBuilder + * + * @run main/othervm vm.mlvm.hiddenloader.stress.byteMutation.Test -stressIterationsFactor 100000 + */ + +package vm.mlvm.hiddenloader.stress.byteMutation; + +import vm.mlvm.hiddenloader.share.HiddenkTestee01; +import vm.mlvm.hiddenloader.share.StressClassLoadingTest; +import vm.share.FileUtils; +import vm.share.options.Option; + +/** + * The test does the following in a cycle: + * + *

      + *
    1. Takes bytes from a valid class file + *
    2. Sets 1 to 5 bytes in random positions to random values + *
    3. Tries to load such class using: + *
        + *
      • a custom class loader, + *
      • {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} + * when {@code -hiddenLoad true} option is passed to the test. + *
      + *
    + * + *

    In most cases the resulting class file is invalid and rejected by + * the VM verifier. But this test tries to find pathological cases, such + * as infinite loops during verification or VM crashes. + * + */ +public class Test extends StressClassLoadingTest { + private final static Class HOST_CLASS = HiddenkTestee01.class; + private final byte[] testeeBytes; + @Option(name = "mutationCount", default_value = "3", + description = "How many bytes to mutate in a class") + private int mutationCount = 3; + + /** + * Constructs the test. + * @throws Exception if there are any errors when + * reading {@link vm.mlvm.hiddenloader.share.HiddenkTestee01} class bytecodes. + */ + public Test() throws Exception { + this.testeeBytes = FileUtils.readClass(HiddenkTestee01.class.getName()); + } + + /** + * Returns {@link vm.mlvm.hiddenloader.share.HiddenkTestee01} class to the + * parent. + * @return {@link vm.mlvm.hiddenloader.share.HiddenkTestee01} class. + */ + @Override + protected Class getHostClass() { + return HOST_CLASS; + } + + /** + * Takes {@link vm.mlvm.hiddenloader.share.HiddenkTestee01} class bytecodes + * and modifies mutationCount bytes setting them to random values. + * @return {@link vm.mlvm.hiddenloader.share.HiddenkTestee01} class bytecodes with modified bytes. + */ + @Override + protected byte[] generateClassBytes() { + // TODO: there is non-zero probability that generated bytecode will be + // valid, so it should be a subject of fuzzing mechanism + byte[] alteredBytes = testeeBytes.clone(); + for (int j = 0; j < mutationCount; ++j) { + alteredBytes[getRNG().nextInt(alteredBytes.length)] = (byte) getRNG().nextInt(256); + } + return alteredBytes; + } + + /** + * Runs the test. + * @param args Test arguments. + */ + public static void main(String[] args) { + StressClassLoadingTest.launch(args); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/byteMutation/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/byteMutation/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/byteMutation/TEST.properties 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/byteMutation/TEST.properties 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 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. +# + +exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 + * @key randomness + * @modules java.base/jdk.internal.misc + * + * @summary converted from VM Testbase vm/mlvm/anonloader/stress/oome/heap. + * VM Testbase keywords: [feature_mlvm, nonconcurrent] + * + * @library /vmTestbase + * /test/lib + * + * @comment build test class and indify classes + * @build vm.mlvm.hiddenloader.stress.oome.heap.Test + * @run driver vm.mlvm.share.IndifiedClassesBuilder + * + * @run main/othervm -XX:-UseGCOverheadLimit -Xmx128m vm.mlvm.hiddenloader.stress.oome.heap.Test + */ + +package vm.mlvm.hiddenloader.stress.oome.heap; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.util.List; +import java.io.IOException; + +import vm.mlvm.hiddenloader.share.HiddenkTestee01; +import vm.mlvm.share.MlvmOOMTest; +import vm.mlvm.share.MlvmTestExecutor; +import vm.mlvm.share.Env; +import vm.share.FileUtils; + +/** + * This test loads a class using defineHiddenClass, creates instances + * of that class and stores them, expecting Heap OOME. + * + */ + +public class Test extends MlvmOOMTest { + @Override + protected void checkOOME(OutOfMemoryError oome) { + String message = oome.getMessage(); + if (!message.startsWith("Java heap space")) { + throw new RuntimeException("TEST FAIL : wrong OOME", oome); + } + } + @Override + protected void eatMemory(List list) { + byte[] classBytes = null; + try { + classBytes = FileUtils.readClass(HiddenkTestee01.class.getName()); + } catch (IOException e) { + Env.throwAsUncheckedException(e); + } + try { + while (true) { + Lookup lookup = MethodHandles.lookup(); + Lookup ank_lookup = MethodHandles.privateLookupIn(HiddenkTestee01.class, lookup); + Class c = ank_lookup.defineHiddenClass(classBytes, true).lookupClass(); + list.add(c.newInstance()); + } + } catch (InstantiationException | IllegalAccessException e) { + Env.throwAsUncheckedException(e); + } + } + + public static void main(String[] args) { + MlvmTestExecutor.launch(args); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/TEST.properties 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/TEST.properties 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 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. +# + +exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/metaspace/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/metaspace/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/metaspace/Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/metaspace/Test.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 + * @modules java.base/jdk.internal.misc + * + * @summary converted from VM Testbase vm/mlvm/anonloader/stress/oome/metaspace. + * VM Testbase keywords: [feature_mlvm, nonconcurrent] + * + * @library /vmTestbase + * /test/lib + * + * @comment build test class and indify classes + * @build vm.mlvm.hiddenloader.stress.oome.metaspace.Test + * @run driver vm.mlvm.share.IndifiedClassesBuilder + * + * @run main/othervm -XX:MaxRAMPercentage=25 -XX:-UseGCOverheadLimit -XX:MetaspaceSize=10m + * -XX:MaxMetaspaceSize=20m vm.mlvm.hiddenloader.stress.oome.metaspace.Test + */ + +package vm.mlvm.hiddenloader.stress.oome.metaspace; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.util.List; +import java.io.IOException; + +import vm.mlvm.hiddenloader.share.HiddenkTestee01; +import vm.mlvm.share.MlvmOOMTest; +import vm.mlvm.share.MlvmTestExecutor; +import vm.mlvm.share.Env; +import vm.share.FileUtils; + +/** + * This test loads classes using defineHiddenClass and stores them, + * expecting Metaspace OOME. + * + */ +public class Test extends MlvmOOMTest { + @Override + protected void checkOOME(OutOfMemoryError oome) { + String message = oome.getMessage(); + if (!"Metaspace".equals(message) && !"Compressed class space".equals(message)) { + throw new RuntimeException("TEST FAIL : wrong OOME", oome); + } + } + + @Override + protected void eatMemory(List list) { + byte[] classBytes = null; + try { + classBytes = FileUtils.readClass(HiddenkTestee01.class.getName()); + } catch (IOException e) { + Env.throwAsUncheckedException(e); + } + try { + while (true) { + Lookup lookup = MethodHandles.lookup(); + Lookup ank_lookup = MethodHandles.privateLookupIn(HiddenkTestee01.class, lookup); + Class c = ank_lookup.defineHiddenClass(classBytes, true).lookupClass(); + list.add(c.newInstance()); + } + } catch (InstantiationException | IllegalAccessException e) { + Env.throwAsUncheckedException(e); + } + } + + public static void main(String[] args) { + MlvmTestExecutor.launch(args); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/metaspace/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/metaspace/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/metaspace/TEST.properties 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/oome/metaspace/TEST.properties 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 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. +# + +exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/parallelLoad/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/parallelLoad/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/parallelLoad/Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/parallelLoad/Test.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 + * @modules java.base/jdk.internal.misc + * + * @summary converted from VM Testbase vm/mlvm/anonloader/stress/parallelLoad. + * VM Testbase keywords: [feature_mlvm, nonconcurrent] + * + * @library /vmTestbase + * /test/lib + * + * @comment build test class and indify classes + * @build vm.mlvm.hiddenloader.stress.parallelLoad.Test + * @run driver vm.mlvm.share.IndifiedClassesBuilder + * + * @run main/othervm + * -Xverify:all + * vm.mlvm.hiddenloader.stress.parallelLoad.Test + * -threadsPerCpu 4 + * -threadsExtra 20 + * -parseTimeout 0 + * -hiddenLoad true + */ + +package vm.mlvm.hiddenloader.stress.parallelLoad; + +import vm.mlvm.hiddenloader.share.StressClassLoadingTest; +import vm.mlvm.hiddenloader.share.HiddenkTestee01; +import vm.mlvm.share.MlvmTestExecutor; +import vm.mlvm.share.MultiThreadedTest; +import vm.share.FileUtils; + +/** + * Verifies that loading classes in parallel from several threads using + * {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} + * does not produce exceptions and crashes. + * + */ +public class Test extends MultiThreadedTest { + private static final Class HOST_CLASS = HiddenkTestee01.class; + private static final String NAME_PREFIX = "thread%03d"; + + private final byte[] classBytes; + + private static class SubTest extends StressClassLoadingTest { + private final byte[] classBytes; + + public SubTest(byte[] classBytes) { + this.classBytes = classBytes; + } + + @Override + protected Class getHostClass() { + return HOST_CLASS; + } + + @Override + protected byte[] generateClassBytes() { + return classBytes; + } + } + + public Test() throws Exception { + classBytes = FileUtils.readClass(HOST_CLASS.getName()); + } + + /** + * Constructs a sub-test class and runs it. The sub-test class loads + * {@link vm.mlvm.hiddenloader.share.HiddenkTestee01} class bytecodes + * using {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} + * @param numThread Number of the thread + * @throws Exception if there any exceptions thrown in the sub-test + */ + @Override + protected boolean runThread(int numThread) throws Exception { + SubTest subTest = new SubTest(classBytes); + subTest.setFileNamePrefix(String.format(NAME_PREFIX, numThread)); + return subTest.run(); + } + + /** + * Runs the test. + * @param args Test arguments. + */ + public static void main(String[] args) { + MlvmTestExecutor.launch(args); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/parallelLoad/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/parallelLoad/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/parallelLoad/TEST.properties 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/parallelLoad/TEST.properties 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 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. +# + +exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/randomBytecodes/Test.java openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/randomBytecodes/Test.java --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/randomBytecodes/Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/randomBytecodes/Test.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 + * @key randomness + * @modules java.base/jdk.internal.misc + * + * @summary converted from VM Testbase vm/mlvm/anonloader/stress/randomBytecodes. + * VM Testbase keywords: [feature_mlvm, nonconcurrent] + * + * @library /vmTestbase + * /test/lib + * + * @comment build test class and indify classes + * @build vm.mlvm.hiddenloader.stress.randomBytecodes.Test + * @run driver vm.mlvm.share.IndifiedClassesBuilder + * + * @run main/othervm vm.mlvm.hiddenloader.stress.randomBytecodes.Test -stressIterationsFactor 100000 + */ + +package vm.mlvm.hiddenloader.stress.randomBytecodes; + +import java.util.Arrays; +import vm.mlvm.hiddenloader.share.StressClassLoadingTest; + +/** + * The test does the following in a cycle: + *
      + *
    1. Creates a class bytecodes that has a valid 12-byte header + * and has totally random bytes after the header + *
    2. Tries to load such class using: + *
        + *
      • a custom class loader, or + *
      • {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass} + * when {@code -hiddenLoad true} is set. + *
      + *
    + * + *

    In most cases the resulting class file is invalid and rejected by + * the VM verifier. But this test is looking for pathological cases + * such as infinite loops in the verifier or VM crashes. + * + */ +public class Test extends StressClassLoadingTest { + private static final Class HOST_CLASS = Test.class; + private static final int MAX_SIZE = 0xFFF7; + private static final byte[] CLASS_HEADER = new byte[] { + (byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, + 0x00, 0x00, 0x00, 0x32 + }; + + /** + * Returns {@link vm.mlvm.hiddenloader.share.HiddenkTestee01} class to the + * parent. + * @return {@link vm.mlvm.hiddenloader.share.HiddenkTestee01} class. + */ + @Override + protected Class getHostClass() { + return HOST_CLASS; + } + + /** + * Generates a class with valid header (magic and version fields) and + * random bytes after the header. + *

    Class size is random ([8..65527]). + * Byte values are limited to [0..11] range in order to increase + * possiblity that the random class passes the initial (dead-on-arrival) + * stages of the verifier and is rejected + * in more interesting ones, like method bytecode verification. + * Class version is 52. + * + * @return Class with valid Java header (8 bytes) and totally random bytes + * after the header + */ + @Override + protected byte[] generateClassBytes() { + final byte[] classBytes = Arrays.copyOf(CLASS_HEADER, + CLASS_HEADER.length + getRNG().nextInt(MAX_SIZE)); + for (int j = CLASS_HEADER.length; j < classBytes.length; j++) { + classBytes[j] = (byte) getRNG().nextInt(12); + } + + return classBytes; + } + + /** + * Runs the test. + * @param args Test arguments. + */ + public static void main(String[] args) { + StressClassLoadingTest.launch(args); + } +} diff -Nru openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/randomBytecodes/TEST.properties openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/randomBytecodes/TEST.properties --- openjdk-17-17.0.3+7/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/randomBytecodes/TEST.properties 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/hotspot/jtreg/vmTestbase/vm/mlvm/hiddenloader/stress/randomBytecodes/TEST.properties 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 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. +# + +exclusiveAccess.dirs=. diff -Nru openjdk-17-17.0.3+7/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathExceptionTest.java openjdk-17-17.0.4+8/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathExceptionTest.java --- openjdk-17-17.0.3+7/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathExceptionTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathExceptionTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 xpath; + +import java.io.StringReader; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +/* + * @test + * @bug 8284548 + * @run testng xpath.XPathExceptionTest + * @summary This is a general test for Exception handling. Additional cases may + * be added with a bug id in the test cases. + */ +public class XPathExceptionTest { + + /* + * DataProvider: invalid XPath expressions + * Illegal expressions and structures that may escape the validation check. + */ + @DataProvider(name = "invalid") + public Object[][] getInvalid() throws Exception { + return new Object[][]{ + // @bug JDK-8284548: expressions ending with relational operators + // throw StringIndexOutOfBoundsException instead of XPathExpressionException + {"/a/b/c[@d >"}, + {"/a/b/c[@d <"}, + {"/a/b/c[@d >="}, + {">>"}, + }; + } + + /** + * Verifies that the XPath processor throws XPathExpressionException upon + * encountering illegal XPath expressions. + * @param invalidExp an illegal XPath expression + * @throws Exception if the test fails + */ + @Test(dataProvider = "invalid") + public void testIllegalExp(String invalidExp) throws Exception { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = builder.parse(new org.xml.sax.InputSource(new StringReader(""))); + Assert.assertThrows(XPathExpressionException.class, () -> evaluate(doc, invalidExp)); + } + + private void evaluate(Document doc, String s) throws XPathExpressionException { + XPath xp = XPathFactory.newInstance().newXPath(); + XPathExpression xe = xp.compile(s); + xe.evaluateExpression(doc, Node.class); + } +} diff -Nru openjdk-17-17.0.3+7/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathExpTest.java openjdk-17-17.0.4+8/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathExpTest.java --- openjdk-17-17.0.3+7/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathExpTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathExpTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 xpath; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/* + * @test + * @bug 8284920 + * @run testng/othervm xpath.XPathExpTest + * @summary Tests for various XPath Expressions. + */ +public class XPathExpTest { + + private static final String XML = + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " "; + private static final String PARENT_CHILD = "child(2)"; + + /* + * DataProvider for XPath expression test. + * Data columns: + * see parameters of the test "test" + */ + @DataProvider(name = "xpathExp") + public Object[][] getXPathExpression() throws Exception { + + return new Object[][]{ + // verifies various forms of the parent axis + {"/root/child[@id='2']", PARENT_CHILD}, + {"//grandchild[@id='3']/parent::child", PARENT_CHILD}, + {"//grandchild[@id='3']/parent::node()", PARENT_CHILD}, + {"//grandchild[@id='3']/parent::*", PARENT_CHILD}, + {"//grandchild[@id='3']/parent::node()/grandchild[@id='4']/parent::node()", PARENT_CHILD}, + {"//grandchild[@id='3']/..", PARENT_CHILD}, + {"//grandchild[@id='3']/../grandchild[@id='4']/..", PARENT_CHILD}, + {"//grandchild[@id='3']/parent::node()/grandchild[@id='4']/..", PARENT_CHILD}, + + // verifies various forms of the self axis + {"/root/child[@id='2']/self::child", PARENT_CHILD}, + {"/root/child[@id='2']/self::node()", PARENT_CHILD}, + {"/root/child[@id='2']/self::*", PARENT_CHILD}, + {"self::node()/root/child[@id='2']", PARENT_CHILD}, + {"/root/child[@id='2']/.", PARENT_CHILD}, + {"./root/child[@id='2']", PARENT_CHILD}, + {".//child[@id='2']", PARENT_CHILD}, + {"//grandchild[@id='3']/./../grandchild[@id='4']/..", PARENT_CHILD}, + {"//grandchild[@id='3']/./parent::node()/grandchild[@id='4']/..", PARENT_CHILD}, + }; + } + + /** + * Verifies XPath expressions. + * + * @param exp XPath expression + * @param expected expected result + * @throws Exception + */ + @Test(dataProvider = "xpathExp") + void test(String exp, String expected) throws Exception { + Document doc = getDoc(XML); + XPath xPath = XPathFactory.newInstance().newXPath(); + NodeList nl = (NodeList) xPath.evaluate(exp, doc, XPathConstants.NODESET); + Node child = nl.item(0); + Assert.assertEquals( + child.getNodeName() + "(" + child.getAttributes().item(0).getNodeValue() + ")", + expected); + } + + Document getDoc(String xml) throws Exception { + DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); + dfactory.setNamespaceAware(true); + DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); + InputStream is = new ByteArrayInputStream(xml.getBytes()); + return docBuilder.parse(is); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/build/AbsPathsInImage.java openjdk-17-17.0.4+8/test/jdk/build/AbsPathsInImage.java --- openjdk-17-17.0.3+7/test/jdk/build/AbsPathsInImage.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/build/AbsPathsInImage.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * 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,6 +48,7 @@ // JTREG=JAVA_OPTIONS=-Djdk.test.build.AbsPathInImage.dir=/path/to/dir public static final String DIR_PROPERTY = "jdk.test.build.AbsPathsInImage.dir"; private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("windows"); + private static final boolean IS_LINUX = System.getProperty("os.name").toLowerCase().contains("linux"); private boolean matchFound = false; @@ -96,6 +97,13 @@ if (buildOutputRoot == null) { throw new Error("Could not find build output root, test cannot run"); } + // Validate the root paths + if (!Paths.get(buildWorkspaceRoot).isAbsolute()) { + throw new Error("Workspace root is not an absolute path: " + buildWorkspaceRoot); + } + if (!Paths.get(buildOutputRoot).isAbsolute()) { + throw new Error("Output root is not an absolute path: " + buildOutputRoot); + } List searchPatterns = new ArrayList<>(); expandPatterns(searchPatterns, buildWorkspaceRoot); @@ -157,7 +165,7 @@ String fileName = file.toString(); if (Files.isSymbolicLink(file)) { return super.visitFile(file, attrs); - } else if (fileName.endsWith(".debuginfo") || fileName.endsWith(".pdb")) { + } else if ((fileName.endsWith(".debuginfo") && !IS_LINUX) || fileName.endsWith(".pdb")) { // Do nothing } else if (fileName.endsWith(".zip")) { scanZipFile(file, searchPatterns); diff -Nru openjdk-17-17.0.3+7/test/jdk/com/sun/jdi/ResumeAfterThreadResumeCallTest.java openjdk-17-17.0.4+8/test/jdk/com/sun/jdi/ResumeAfterThreadResumeCallTest.java --- openjdk-17-17.0.3+7/test/jdk/com/sun/jdi/ResumeAfterThreadResumeCallTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/com/sun/jdi/ResumeAfterThreadResumeCallTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2021 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 + * 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 8274687 + * @summary Test the special handling in the JDWP agent of threads that call + * j.l.Thread.resume(). + * + * This is the sequence of actions by the debugger and the threads + * "main" and "resumee" in the target vm. + * + * "resumee": Reaches breakpoint in methodWithBreakpoint() and is + * suspended then. + * + * "main": Calls j.l.Thread.resume() for "resumee". There is an internal + * breakpoint in Thread.resume() so the JDWP agent receives a + * breakpoint event. It finds that "resumee" is suspended because + * of JDWP actions. The resume() call would interfere with the + * debugger therefore "main" is blocked. + * + * Debugger: Tests if the suspended "resumee" can be suspended a second + * time and resumes it again. + * + * Debugger: Resumes "resumee" by calling ThreadReference.resume(). + * The JDWP agent notifies "main" about it. + * + * "resumee": Continues execution. + * + * "main": Receives the notification, finds that "resumee" is not + * suspended anymore and continues execution. + * + * Debugger: Verifies that "main" is no longer blocked. + * + * @author Richard Reingruber richard DOT reingruber AT sap DOT com + * + * @library /test/lib + * + * @run build TestScaffold VMConnection TargetListener TargetAdapter + * @run compile -g ResumeAfterThreadResumeCallTest.java + * @run driver ResumeAfterThreadResumeCallTest + */ +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import jdk.test.lib.Asserts; + +import java.util.*; + +// Target program for the debugger +class ResumeAfterThreadResumeCallTarg extends Thread { + + public boolean reachedBreakpoint; + public boolean mainThreadReturnedFromResumeCall; + public boolean testFinished; + + public ResumeAfterThreadResumeCallTarg(String name) { + super(name); + } + + public static void log(String m) { + String threadName = Thread.currentThread().getName(); + System.out.println("###(Target,"+ threadName +") " + m); + } + + public static void main(String[] args) { + log("Entered main()"); + + // Start "resumee" thread. + ResumeAfterThreadResumeCallTarg resumee = new ResumeAfterThreadResumeCallTarg("resumee"); + resumee.start(); + + // Wait for "resumee" to reach the breakpoint in methodWithBreakpoint(). + while (!resumee.reachedBreakpoint) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { /* ignored */ } + } + + // "resumee" is suspended now because of the breakpoint + // Calling Thread.resume() will block this thread. + log("Calling Thread.resume()"); + resumee.resume(); + resumee.mainThreadReturnedFromResumeCall = true; + log("Thread.resume() returned"); + + // Wait for debugger + while (!resumee.testFinished) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { /* ignored */ } + } + } + + public void run() { + log("up and running."); + methodWithBreakpoint(); + } + + public void methodWithBreakpoint() { + log("Entered methodWithBreakpoint()"); + } +} + + +// Debugger program + +public class ResumeAfterThreadResumeCallTest extends TestScaffold { + public static final String TARGET_CLS_NAME = ResumeAfterThreadResumeCallTarg.class.getName(); + public static final long UNBLOCK_TIMEOUT = 10000; + + ResumeAfterThreadResumeCallTest (String args[]) { + super(args); + } + + public static void main(String[] args) throws Exception { + new ResumeAfterThreadResumeCallTest(args).startTests(); + } + + /** + * Set a breakpoint in the given method and resume all threads. The + * breakpoint is configured to suspend just the thread that reaches it + * instead of all threads. + */ + public BreakpointEvent resumeTo(String clsName, String methodName, String signature) { + boolean suspendThreadOnly = true; + return resumeTo(clsName, methodName, signature, suspendThreadOnly); + } + + protected void runTests() throws Exception { + BreakpointEvent bpe = startToMain(TARGET_CLS_NAME); + mainThread = bpe.thread(); + + log("Resuming to methodWithBreakpoint()"); + bpe = resumeTo(TARGET_CLS_NAME, "methodWithBreakpoint", "()V"); + + log("Thread \"resumee\" has reached the breakpoint and is suspended now."); + ThreadReference resumee = bpe.thread(); + ObjectReference resumeeThreadObj = resumee.frame(1).thisObject(); + printStack(resumee); + mainThread.suspend(); + printStack(mainThread); + mainThread.resume(); + log("resumee.isSuspended() -> " + resumee.isSuspended()); + log("mainThread.isSuspended() -> " + mainThread.isSuspended()); + log("Notify target main thread to continue by setting reachedBreakpoint = true."); + setField(resumeeThreadObj, "reachedBreakpoint", vm().mirrorOf(true)); + + log("Sleeping 500ms so that the main thread is blocked calling Thread.resume() on \"resumee\" Thread."); + Thread.sleep(500); + log("After sleep."); + mainThread.suspend(); + printStack(mainThread); + mainThread.resume(); + + boolean mainThreadReturnedFromResumeCall = false; + boolean resumedResumee = false; + for (long sleepTime = 50; sleepTime < UNBLOCK_TIMEOUT && !mainThreadReturnedFromResumeCall; sleepTime <<= 1) { + log("mainThread.isSuspended() -> " + mainThread.isSuspended()); + Value v = getField(resumeeThreadObj, "mainThreadReturnedFromResumeCall"); + mainThreadReturnedFromResumeCall = ((PrimitiveValue) v).booleanValue(); + if (!resumedResumee) { + // main thread should still be blocked. + Asserts.assertFalse(mainThreadReturnedFromResumeCall, "main Thread was not blocked"); + + // Test suspending the already suspended resumee thread. + Asserts.assertTrue(resumee.isSuspended(), "\"resumee\" is not suspended."); + log("Check if suspended \"resumee\" can be suspended a 2nd time."); + resumee.suspend(); + log("resumee.isSuspended() -> " + resumee.isSuspended()); + log("Resuming \"resumee\""); + resumee.resume(); + Asserts.assertTrue(resumee.isSuspended(), "\"resumee\" is not suspended."); + + // Really resume the resumee thread. + log("Resuming \"resumee\" a 2nd time will unblock the main thread."); + resumee.resume(); + Asserts.assertFalse(resumee.isSuspended(), "\"resumee\" is still suspended."); + resumedResumee = true; + } + log("Sleeping " + sleepTime + "ms"); + Thread.sleep(sleepTime); + } + Asserts.assertTrue(mainThreadReturnedFromResumeCall, "main Thread was not unblocked"); + + setField(resumeeThreadObj, "testFinished", vm().mirrorOf(true)); + + // Resume the target listening for events + listenUntilVMDisconnect(); + } + + public void printStack(ThreadReference thread) throws Exception { + log("Stack of thread '" + thread.name() + "':"); + List stack_frames = thread.frames(); + int i = 0; + for (StackFrame ff : stack_frames) { + Location loc = ff.location(); + String locString = "bci:" + loc.codeIndex(); + try { + locString = loc.sourceName() + ":" + loc.lineNumber() + "," + locString; + } catch (AbsentInformationException e) {/* empty */}; + log(" frame[" + i++ +"]: " + ff.location().method() + " (" + locString + ")"); + } + } + + public void setField(ObjectReference obj, String fName, Value val) throws Exception { + log("set field " + fName + " = " + val); + ReferenceType rt = obj.referenceType(); + Field fld = rt.fieldByName(fName); + obj.setValue(fld, val); + log("ok"); + } + + public Value getField(ObjectReference obj, String fName) throws Exception { + log("get field " + fName); + ReferenceType rt = obj.referenceType(); + Field fld = rt.fieldByName(fName); + Value val = obj.getValue(fld); + log("result : " + val); + return val; + } + + public void log(String m) { + System.out.println("###(Debugger) " + m); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java openjdk-17-17.0.4+8/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java --- openjdk-17-17.0.3+7/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8245527 * @library lib/ /test/lib + * @modules java.base/sun.security.util * @run main/othervm LdapCBPropertiesTest true true com.sun.jndi.ldap.tls.cbtype tls-server-end-point * @run main/othervm LdapCBPropertiesTest false false com.sun.jndi.ldap.tls.cbtype tls-server-end-point * @run main/othervm LdapCBPropertiesTest true true com.sun.jndi.ldap.tls.cbtype tls-server-end-point com.sun.jndi.ldap.connect.timeout 2000 @@ -53,6 +54,8 @@ import jdk.test.lib.net.URIBuilder; +import sun.security.util.ChannelBindingException; + public class LdapCBPropertiesTest { /* * Where do we find the keystores? @@ -187,7 +190,8 @@ } } } - if (!shouldPass && ne.getRootCause() == null) { + Throwable rc = ne.getRootCause(); + if (!shouldPass && (rc == null || rc instanceof ChannelBindingException)) { // Expected exception caused by Channel Binding parameter inconsistency return true; } diff -Nru openjdk-17-17.0.3+7/test/jdk/com/sun/org/apache/xml/internal/security/ShortECDSA.java openjdk-17-17.0.4+8/test/jdk/com/sun/org/apache/xml/internal/security/ShortECDSA.java --- openjdk-17-17.0.3+7/test/jdk/com/sun/org/apache/xml/internal/security/ShortECDSA.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/com/sun/org/apache/xml/internal/security/ShortECDSA.java 2022-07-14 08:05:38.000000000 +0000 @@ -25,9 +25,12 @@ * @test * @bug 8259535 * @summary ECDSA SignatureValue do not always have the specified length - * @modules java.xml.crypto + * @modules java.xml.crypto/com.sun.org.apache.xml.internal.security + * java.xml.crypto/com.sun.org.apache.xml.internal.security.signature */ +import com.sun.org.apache.xml.internal.security.Init; +import com.sun.org.apache.xml.internal.security.signature.XMLSignature; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; @@ -89,6 +92,18 @@ if (sig.length != 64) { System.out.println("Length: " + sig.length); System.out.println(HexFormat.ofDelimiter(":").formatHex(sig)); + throw new RuntimeException("Failed"); + } + + // Internal way + Init.init(); + XMLSignature signature = new XMLSignature(document, null, + SignatureMethod.ECDSA_SHA256, CanonicalizationMethod.INCLUSIVE); + signature.sign(privateKey); + sig = signature.getSignatureValue(); + if (sig.length != 64) { + System.out.println("Length: " + sig.length); + System.out.println(HexFormat.ofDelimiter(":").formatHex(sig)); throw new RuntimeException("Failed"); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/com/sun/org/apache/xml/internal/security/signature-enveloping-hmac-sha1-keyinfo.xml openjdk-17-17.0.4+8/test/jdk/com/sun/org/apache/xml/internal/security/signature-enveloping-hmac-sha1-keyinfo.xml --- openjdk-17-17.0.3+7/test/jdk/com/sun/org/apache/xml/internal/security/signature-enveloping-hmac-sha1-keyinfo.xml 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/com/sun/org/apache/xml/internal/security/signature-enveloping-hmac-sha1-keyinfo.xml 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,25 @@ + + + + + + + + 7/XTsHaBSOnJ/jXD5v0zL6VKYsk= + + + + JElPttIT4Am7Q+MNoMyv+WDfAZw= + + + testText + + + + BAds672US3sCYunM2k2bEQLbuRxdQlNTvq+5fitOpDMe0mBdZV4J3yZaG0taziYIuAT9GJGfds+q + xtXOCNWe/60= + + + + some text + \ No newline at end of file diff -Nru openjdk-17-17.0.3+7/test/jdk/com/sun/org/apache/xml/internal/security/SignatureKeyInfo.java openjdk-17-17.0.4+8/test/jdk/com/sun/org/apache/xml/internal/security/SignatureKeyInfo.java --- openjdk-17-17.0.3+7/test/jdk/com/sun/org/apache/xml/internal/security/SignatureKeyInfo.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/com/sun/org/apache/xml/internal/security/SignatureKeyInfo.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8272908 + * @summary Verify signature KeyInfo + * @library /test/lib + * @modules java.xml.crypto/com.sun.org.apache.xml.internal.security + * java.xml.crypto/com.sun.org.apache.xml.internal.security.c14n + * java.xml.crypto/com.sun.org.apache.xml.internal.security.signature + * java.xml.crypto/com.sun.org.apache.xml.internal.security.utils + * java.xml.crypto/com.sun.org.apache.xml.internal.security.keys + * java.xml.crypto/com.sun.org.apache.xml.internal.security.keys.content.keyvalues + * java.xml.crypto/com.sun.org.apache.xml.internal.security.keys.content + * java.xml.crypto/com.sun.org.apache.xml.internal.security.exceptions + * @run main/othervm SignatureKeyInfo + */ + +import com.sun.org.apache.xml.internal.security.Init; +import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; +import com.sun.org.apache.xml.internal.security.keys.KeyInfo; +import com.sun.org.apache.xml.internal.security.keys.content.PGPData; +import com.sun.org.apache.xml.internal.security.keys.content.RetrievalMethod; +import com.sun.org.apache.xml.internal.security.keys.content.SPKIData; +import com.sun.org.apache.xml.internal.security.signature.XMLSignature; +import com.sun.org.apache.xml.internal.security.utils.Constants; +import com.sun.org.apache.xml.internal.security.utils.XMLUtils; +import com.sun.org.apache.xml.internal.security.utils.ElementProxy; +import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.RSAKeyValue; +import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.DSAKeyValue; + +import jdk.test.lib.Asserts; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + + +import javax.xml.crypto.dsig.CanonicalizationMethod; +import javax.xml.crypto.dsig.SignatureMethod; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.File; +import java.math.BigInteger; +import java.security.*; + +import static jdk.test.lib.Asserts.assertEquals; + +public class SignatureKeyInfo { + + private final static String DIR = System.getProperty("test.src", "."); + private static DocumentBuilderFactory dbf = null; + private static Document doc; + + private static final String NAME = "testName"; + private static final String TEXT = "testText"; + private static final String NS = Constants.SignatureSpecNS; + private static final String RSA = "RSA"; + private static final String DSA = "DSA"; + private static final String FILE_TO_SIGN = "signature-enveloping-hmac-sha1.xml"; + private static final String FILE_TO_VERIFY = "signature-enveloping-hmac-sha1-keyinfo.xml"; + private static final int FIRST_EL = 0; + + public static void main(String[] args) throws Exception { + + Init.init(); + dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + verifyXmlKeyInfo(); + sign(RSA); + sign(DSA); + } + + private static void sign(String algorithm) throws Exception { + File file = new File(DIR, FILE_TO_SIGN); + + doc = dbf.newDocumentBuilder().parse(file); + + KeyPair kp = getKeyPair(algorithm); + + String signMethod = RSA.equals(algorithm) ? SignatureMethod.RSA_SHA256 + : SignatureMethod.DSA_SHA256; + + XMLSignature signature = new XMLSignature(doc, null, + signMethod, CanonicalizationMethod.INCLUSIVE); + + signature.addKeyInfo(kp.getPublic()); + KeyInfo keyInfo = signature.getKeyInfo(); + addKeyInfoData(keyInfo, algorithm); + signature.sign(kp.getPrivate()); + } + + private static Element getSignElement() { + NodeList nl = + doc.getElementsByTagNameNS(NS, "Signature"); + if (nl.getLength() == 0) { + throw new RuntimeException("Could not find signature Element"); + } + + return (Element) nl.item(FIRST_EL); + } + + private static void addKeyInfoData(KeyInfo keyInfo, String algorithm) throws Exception { + KeyPair keyPair = getKeyPair(algorithm); + + if (algorithm.equals(RSA)) { + RSAKeyValue rsaKeyValue = new RSAKeyValue(doc, keyPair.getPublic()); + keyInfo.add(rsaKeyValue); + } else { + DSAKeyValue dsaKeyValue = new DSAKeyValue(doc, keyPair.getPublic()); + keyInfo.add(dsaKeyValue); + } + + Element elpgp= doc.createElementNS(NS, Constants._TAG_PGPDATA); + Element elrm= doc.createElementNS(NS, Constants._TAG_RETRIEVALMETHOD); + Element elspki= doc.createElementNS(NS, Constants._TAG_SPKIDATA); + keyInfo.add(new PGPData(elpgp, NS)); + keyInfo.add(new RetrievalMethod(elrm, NS)); + keyInfo.add(new SPKIData(elspki, NS)); + + keyInfo.setId(TEXT); + keyInfo.addKeyName(TEXT); + keyInfo.add(keyPair.getPublic()); + keyInfo.addKeyValue(keyPair.getPublic()); + keyInfo.addDEREncodedKeyValue(keyPair.getPublic()); + keyInfo.addKeyInfoReference(NS); + keyInfo.addMgmtData(TEXT); + + Element e = XMLUtils.createElementInSignatureSpace(doc, NAME); + keyInfo.addKeyValue(e); + keyInfo.addUnknownElement(e); + keyInfo.addText(TEXT); + keyInfo.addTextElement(TEXT, NAME); + keyInfo.addBigIntegerElement(BigInteger.valueOf(12345), NAME); + keyInfo.addBase64Text(TEXT.getBytes()); + keyInfo.addBase64Element(TEXT.getBytes(), NAME); + + verifyKeyInfoData(keyInfo, algorithm); + } + + private static KeyPair getKeyPair(String algorithm) throws NoSuchAlgorithmException { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm); + keyGen.initialize(2048); + + return keyGen.genKeyPair(); + } + + private static void verifyKeyInfoData(KeyInfo keyInfo, String algorithm) + throws XMLSecurityException { + Asserts.assertTrue(keyInfo.containsKeyName()); + verifyElementText(keyInfo.itemKeyName(FIRST_EL)); + Asserts.assertTrue(keyInfo.containsKeyValue()); + verifyElementNS(keyInfo.itemKeyValue(FIRST_EL).getBaseNamespace()); + + Asserts.assertTrue(keyInfo.containsKeyInfoReference()); + verifyElementNS(keyInfo.itemKeyInfoReference(FIRST_EL).getURI()); + Asserts.assertTrue(keyInfo.containsDEREncodedKeyValue()); + Asserts.assertTrue(keyInfo.containsMgmtData()); + verifyElementText(keyInfo.itemMgmtData(FIRST_EL)); + Asserts.assertEquals(TEXT, keyInfo.getId()); + + Asserts.assertTrue(keyInfo.containsPGPData()); + verifyElementNS(keyInfo.itemPGPData(FIRST_EL).getBaseNamespace()); + + Asserts.assertTrue(keyInfo.containsRetrievalMethod()); + verifyElementNS(keyInfo.itemRetrievalMethod(FIRST_EL).getBaseNamespace()); + Asserts.assertTrue(keyInfo.containsSPKIData()); + verifyElementNS(keyInfo.itemSPKIData(FIRST_EL).getBaseNamespace()); + + Asserts.assertTrue(keyInfo.containsUnknownElement()); + Asserts.assertEquals(NAME, keyInfo.itemUnknownElement(13).getLocalName()); + + Asserts.assertFalse(keyInfo.isEmpty()); + Asserts.assertEquals(algorithm, keyInfo.getPublicKey().getAlgorithm()); + } + + private static void verifyXmlKeyInfo() throws Exception { + File file = new File(DIR, FILE_TO_VERIFY); + + doc = dbf.newDocumentBuilder().parse(file); + Element sigElement = getSignElement(); + XMLSignature signature = new XMLSignature + (sigElement, file.toURI().toString()); + + KeyInfo keyInfo = signature.getKeyInfo(); + assertEquals(TEXT, keyInfo.itemMgmtData(FIRST_EL).getMgmtData()); + } + + private static void verifyElementText(ElementProxy elementProxy) { + Asserts.assertEquals(TEXT, elementProxy.getTextFromTextChild()); + } + + private static void verifyElementNS(String actualNs) { + Asserts.assertEquals(NS, actualNs); + } +} \ No newline at end of file diff -Nru openjdk-17-17.0.3+7/test/jdk/com/sun/org/apache/xml/internal/security/TruncateHMAC.java openjdk-17-17.0.4+8/test/jdk/com/sun/org/apache/xml/internal/security/TruncateHMAC.java --- openjdk-17-17.0.3+7/test/jdk/com/sun/org/apache/xml/internal/security/TruncateHMAC.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/com/sun/org/apache/xml/internal/security/TruncateHMAC.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. * 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 com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.utils.Constants; +import static java.nio.charset.StandardCharsets.US_ASCII; public class TruncateHMAC { @@ -64,7 +65,11 @@ validate("signature-enveloping-hmac-sha1-trunclen-8-attack.xml", false); // this one should pass validate("signature-enveloping-hmac-sha1.xml", true); - generate_hmac_sha1_40(); + + // There are multiple validations regarding hmac min output length, therefore + // checking different values will exercise multiple code blocks + generate_hmac_sha1(40); + generate_hmac_sha1(128); if (atLeastOneFailed) { throw new Exception @@ -86,7 +91,7 @@ try { XMLSignature signature = new XMLSignature (sigElement, file.toURI().toString()); - SecretKey sk = signature.createSecretKey("secret".getBytes("ASCII")); + SecretKey sk = signature.createSecretKey("secret".getBytes(US_ASCII)); System.out.println ("Validation status: " + signature.checkSignatureValue(sk)); if (!pass) { @@ -106,15 +111,15 @@ } } - private static void generate_hmac_sha1_40() throws Exception { - System.out.println("Generating "); + private static void generate_hmac_sha1(int hmacOutputLength) throws Exception { + System.out.println("Generating " + hmacOutputLength); Document doc = dbf.newDocumentBuilder().newDocument(); try { XMLSignature sig = new XMLSignature - (doc, null, XMLSignature.ALGO_ID_MAC_HMAC_SHA1, 40, + (doc, null, XMLSignature.ALGO_ID_MAC_HMAC_SHA1, hmacOutputLength, Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); - sig.sign(getSecretKey("secret".getBytes("ASCII"))); + sig.sign(getSecretKey("secret".getBytes(US_ASCII))); System.out.println("FAILED"); atLeastOneFailed = true; } catch (XMLSignatureException xse) { diff -Nru openjdk-17-17.0.3+7/test/jdk/java/awt/a11y/AccessibleActionsTest.java openjdk-17-17.0.4+8/test/jdk/java/awt/a11y/AccessibleActionsTest.java --- openjdk-17-17.0.3+7/test/jdk/java/awt/a11y/AccessibleActionsTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/awt/a11y/AccessibleActionsTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8281338 + * @summary Test for an element that has more than one Accessibility Action + * @author Artem.Semenov@jetbrains.com + * @run main/manual AccessibleActionsTest + * @requires (os.family == "mac") + */ + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.swing.*; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Hashtable; +import java.util.concurrent.CountDownLatch; + +public class AccessibleActionsTest extends AccessibleComponentTest { + + @Override + public CountDownLatch createCountDownLatch() { + return new CountDownLatch(1); + } + + void createTest() { + INSTRUCTIONS = "INSTRUCTIONS:\n" + + "Check a11y actions.\n\n" + + "Turn screen reader on, and Tab to the label.\n\n" + + "Perform the VO action \"Press\" (VO+space)\n" + + "Perform the VO action \"Show menu\" (VO+m)\n\n" + + "If after the first action the text of the label has changed, and after the second action the menu appears tab further and press PASS, otherwise press FAIL."; + + exceptionString = "AccessibleAction test failed!"; + super.createUI(new AccessibleActionsTestFrame(), "AccessibleActionsTest"); + } + + void createTree() { + INSTRUCTIONS = "INSTRUCTIONS:\n" + + "Check a11y actions.\n\n" + + "Turn screen reader on, and Tab to the label.\n\n" + + "Perform the VO action \"Press\" (VO+space) on tree nodes\n\n" + + "If after press the tree node is expanded tab further and press PASS, otherwise press FAIL."; + + String root = "Root"; + String[] nodes = new String[] {"One node", "Two node"}; + String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"}, + {"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}}; + + Hashtable data = new Hashtable(); + for (int i = 0; i < nodes.length; i++) { + data.put(nodes[i], leafs[i]); + } + + JTree tree = new JTree(data); + tree.setRootVisible(true); + + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + JScrollPane scrollPane = new JScrollPane(tree); + panel.add(scrollPane); + panel.setFocusable(false); + + exceptionString = "AccessibleAction test failed!"; + super.createUI(panel, "AccessibleActionsTest"); + } + + public static void main(String[] args) throws Exception { + AccessibleActionsTest test = new AccessibleActionsTest(); + + countDownLatch = test.createCountDownLatch(); + SwingUtilities.invokeLater(test::createTest); + countDownLatch.await(); + + if (!testResult) { + throw new RuntimeException(a11yTest.exceptionString); + } + + countDownLatch = test.createCountDownLatch(); + SwingUtilities.invokeLater(test::createTree); + countDownLatch.await(); + + if (!testResult) { + throw new RuntimeException(a11yTest.exceptionString); + } + } + + private class AccessibleActionsTestFrame extends JPanel { + + public AccessibleActionsTestFrame() { + MyLabel label = new MyLabel("I'm waiting for the push"); + label.setComponentPopupMenu(createPopup()); + label.setFocusable(true); + add(label); + setLayout(new FlowLayout()); + } + + private static class MyLabel extends JLabel { + public MyLabel(String text) { + super(text); + } + + @Override + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new MyAccessibleJLabel(); + } + return accessibleContext; + } + + private class MyAccessibleJLabel extends JLabel.AccessibleJLabel { + @Override + public AccessibleAction getAccessibleAction() { + return new AccessibleAction() { + @Override + public int getAccessibleActionCount() { + return 2; + } + + @Override + public String getAccessibleActionDescription(int i) { + if (i == 0) { + return AccessibleAction.CLICK; + } + return AccessibleAction.TOGGLE_POPUP; + } + + @Override + public boolean doAccessibleAction(int i) { + if (i == 0) { + changeText(MyLabel.this, "label is pressed"); + return true; + } + JPopupMenu popup = createPopup(); + popup.show(MyLabel.this, 0, 0); + return true; + } + }; + } + } + } + + private static JPopupMenu createPopup() { + JPopupMenu popup = new JPopupMenu("MENU"); + popup.add("One"); + popup.add("Two"); + popup.add("Three"); + return popup; + } + + private static void changeText(JLabel label, String text) { + label.setText(text); + } + + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java openjdk-17-17.0.4+8/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java --- openjdk-17-17.0.3+7/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8240756 + * @summary Non-English characters are printed with wrong glyphs on MacOS + * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops java.desktop/sun.font + * @requires os.family == "mac" + * @run main MultiSlotFontTest + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.image.BufferedImage; +import sun.font.StandardGlyphVector; +import sun.java2d.OSXOffScreenSurfaceData; +import sun.java2d.SunGraphics2D; +import sun.java2d.SurfaceData; +import sun.java2d.loops.SurfaceType; + +public class MultiSlotFontTest { + + private static final int WIDTH = 100; + private static final int HEIGHT = 60; + + private static final String TEST_STR = "\u3042\u3044\u3046\u3048\u304Aabc"; + private static final int EXPECTED_HEIGHT = 10; + private static final int EXPECTED_WIDTH = 77; + private static final int LIMIT_DIFF_HEIGHT = 3; + private static final int LIMIT_DIFF_WIDTH = 15; + + public static void main(String[] args) throws Exception { + MultiSlotFontTest test = new MultiSlotFontTest(); + } + + public MultiSlotFontTest() { + BufferedImage img = createImage(); + + SurfaceData sd = OSXOffScreenSurfaceData.createDataIC(img, + SurfaceType.IntRgb); + SunGraphics2D g2d = new SunGraphics2D(sd, + Color.BLACK, Color.WHITE, null); + Font font = g2d.getFont(); + + if (font.canDisplayUpTo(TEST_STR) != -1) { + System.out.println("There is no capable font. Skipping the test."); + System.out.println("Font: " + font); + return; + } + + FontRenderContext frc = new FontRenderContext(null, false, false); + StandardGlyphVector gv = new StandardGlyphVector(font, TEST_STR, frc); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.drawGlyphVector(gv, 0.0f, (float)(HEIGHT - 5)); + g2d.dispose(); + + Dimension d = getBounds(img); + + if (Math.abs(d.height - EXPECTED_HEIGHT) > LIMIT_DIFF_HEIGHT || + Math.abs(d.width - EXPECTED_WIDTH) > LIMIT_DIFF_WIDTH) { + debugOut(img); + throw new RuntimeException( + "Incorrect GlyphVector shape " + d + "," + gv); + } + } + + private static BufferedImage createImage() { + BufferedImage image = new BufferedImage(WIDTH, HEIGHT, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, WIDTH, HEIGHT); + g.dispose(); + return image; + } + + private Dimension getBounds(BufferedImage img) { + int top = HEIGHT; + int left = WIDTH; + int right = 0; + int bottom = 0; + for (int y = 0; y < HEIGHT; y++) { + for (int x = 0; x < WIDTH; x++) { + if ((img.getRGB(x, y) & 0xFFFFFF) == 0) { + if (top > y) top = y; + if (bottom < y) bottom = y; + if (left > x) left = x; + if (right < x) right = x; + } + } + } + return new Dimension(right - left, bottom - top); + } + + private void debugOut(BufferedImage img) { + for (int y = 0; y < HEIGHT; y++) { + for (int x = 0; x < WIDTH; x++) { + int c = img.getRGB(x, y) & 0xFFFFFF; + if (c == 0) { + System.out.print("*"); + } else { + System.out.print(" "); + } + } + System.out.println(); + } + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/awt/image/DrawImage/ByteIndexedDitherTest.java openjdk-17-17.0.4+8/test/jdk/java/awt/image/DrawImage/ByteIndexedDitherTest.java --- openjdk-17-17.0.3+7/test/jdk/java/awt/image/DrawImage/ByteIndexedDitherTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/awt/image/DrawImage/ByteIndexedDitherTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8280964 + * @summary Tests that drawing to a ByteIndexed image dithers correctly. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +public class ByteIndexedDitherTest { + + public static void main(String[] args) { + BufferedImage bgr = createBGRImage(); + BufferedImage indexed = createIndexedImage(bgr); + checkImage(indexed); + } + + static BufferedImage createBGRImage() { + + int sz = 8; + BufferedImage img; + img = new BufferedImage(sz, sz, BufferedImage.TYPE_3BYTE_BGR); + Graphics2D g = img.createGraphics(); + Color c = new Color(0, 0, 254); + g.setColor(c); + g.fillRect(0, 0, sz, sz); + g.dispose(); + + return img; + } + + static BufferedImage createIndexedImage(BufferedImage srcImage) { + + int w = srcImage.getWidth(null); + int h = srcImage.getHeight(null); + BufferedImage + indexedImg = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED); + Graphics2D g = indexedImg.createGraphics(); + g.drawImage(srcImage, 0, 0, w, h, null); + g.dispose(); + return indexedImg; + } + + static void checkImage(BufferedImage image) { + int wid = image.getWidth(); + int hgt = image.getHeight(); + for (int y=0; y { + protected String computeValue(Class cl) { + // Return string that is not interned and specific to class + return "ClassCache-" + cl.getName(); + } + + public String get(Class cl) { + return super.get(cl); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/io/ClassCache/java.base/java/io/NullClassCache.java openjdk-17-17.0.4+8/test/jdk/java/io/ClassCache/java.base/java/io/NullClassCache.java --- openjdk-17-17.0.3+7/test/jdk/java/io/ClassCache/java.base/java/io/NullClassCache.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/io/ClassCache/java.base/java/io/NullClassCache.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +public class NullClassCache extends ClassCache { + protected Object computeValue(Class cl) { + return null; + } + + public Object get(Class cl) { + return super.get(cl); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/io/ClassCache/NullValueTest.java openjdk-17-17.0.4+8/test/jdk/java/io/ClassCache/NullValueTest.java --- openjdk-17-17.0.3+7/test/jdk/java/io/ClassCache/NullValueTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/io/ClassCache/NullValueTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.NullClassCache; + +/** + * @test + * @bug 8280041 + * @summary Test that ClassCache throws on trying to pass null value + * @compile/module=java.base java/io/NullClassCache.java + * @run main NullValueTest + */ +public class NullValueTest { + public static void main(String... args) throws Throwable { + try { + new NullClassCache().get(Object.class); + throw new IllegalStateException("Should have failed"); + } catch (NullPointerException npe) { + // Expected + } + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/io/FileOutputStream/OpenNUL.java openjdk-17-17.0.4+8/test/jdk/java/io/FileOutputStream/OpenNUL.java --- openjdk-17-17.0.3+7/test/jdk/java/io/FileOutputStream/OpenNUL.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/io/FileOutputStream/OpenNUL.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8285445 + * @requires (os.family == "windows") + * @summary Verify behavior of opening "NUL:" with ADS enabled and disabled. + * @run main/othervm OpenNUL + * @run main/othervm -Djdk.io.File.enableADS OpenNUL + * @run main/othervm -Djdk.io.File.enableADS=FalsE OpenNUL + * @run main/othervm -Djdk.io.File.enableADS=true OpenNUL + */ + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class OpenNUL { + public static void main(String args[]) throws IOException { + String enableADS = System.getProperty("jdk.io.File.enableADS", "true"); + boolean fails = enableADS.equalsIgnoreCase(Boolean.FALSE.toString()); + + FileOutputStream fos; + try { + fos = new FileOutputStream("NUL:"); + if (fails) + throw new RuntimeException("Should have failed"); + } catch (FileNotFoundException fnfe) { + if (!fails) + throw new RuntimeException("Should not have failed"); + } + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java openjdk-17-17.0.4+8/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java --- openjdk-17-17.0.3+7/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/io/ObjectStreamClass/ObjectStreamClassCaching.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.io.ObjectStreamClass; +import java.io.Serializable; +import java.util.ArrayList; +import org.testng.annotations.Test; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +/* @test + * @bug 8277072 + * @library /test/lib/ + * @summary ObjectStreamClass caches keep ClassLoaders alive + * @run testng/othervm -Xmx10m -XX:SoftRefLRUPolicyMSPerMB=1 ObjectStreamClassCaching + */ +public class ObjectStreamClassCaching { + + @Test + public void testCachingEffectiveness() throws Exception { + var ref = lookupObjectStreamClass(TestClass.class); + System.gc(); + Thread.sleep(100L); + // to trigger any ReferenceQueue processing... + lookupObjectStreamClass(AnotherTestClass.class); + assertFalse(ref.refersTo(null), + "Cache lost entry although memory was not under pressure"); + } + + @Test + public void testCacheReleaseUnderMemoryPressure() throws Exception { + var ref = lookupObjectStreamClass(TestClass.class); + pressMemoryHard(ref); + System.gc(); + Thread.sleep(100L); + assertTrue(ref.refersTo(null), + "Cache still has entry although memory was pressed hard"); + } + + // separate method so that the looked-up ObjectStreamClass is not kept on stack + private static WeakReference lookupObjectStreamClass(Class cl) { + return new WeakReference<>(ObjectStreamClass.lookup(cl)); + } + + private static void pressMemoryHard(Reference ref) { + try { + var list = new ArrayList<>(); + while (!ref.refersTo(null)) { + list.add(new byte[1024 * 1024 * 64]); // 64 MiB chunks + } + } catch (OutOfMemoryError e) { + // release + } + } +} + +class TestClass implements Serializable { +} + +class AnotherTestClass implements Serializable { +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/io/ObjectStreamClass/TestOSCClassLoaderLeak.java openjdk-17-17.0.4+8/test/jdk/java/io/ObjectStreamClass/TestOSCClassLoaderLeak.java --- openjdk-17-17.0.3+7/test/jdk/java/io/ObjectStreamClass/TestOSCClassLoaderLeak.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/io/ObjectStreamClass/TestOSCClassLoaderLeak.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.ObjectStreamClass; +import java.io.ObjectStreamField; +import java.io.Serializable; +import java.util.Arrays; +import org.testng.annotations.Test; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import jdk.test.lib.util.ForceGC; + +/* @test + * @bug 8277072 + * @library /test/lib/ + * @build jdk.test.lib.util.ForceGC + * @summary ObjectStreamClass caches keep ClassLoaders alive + * @run testng TestOSCClassLoaderLeak + */ +public class TestOSCClassLoaderLeak { + + @Test + public void testClassLoaderLeak() throws Exception { + TestClassLoader myOwnClassLoader = new TestClassLoader(); + Class loadClass = myOwnClassLoader.loadClass("ObjectStreamClass_MemoryLeakExample"); + Constructor con = loadClass.getConstructor(); + con.setAccessible(true); + Object objectStreamClass_MemoryLeakExample = con.newInstance(); + objectStreamClass_MemoryLeakExample.toString(); + + WeakReference myOwnClassLoaderWeakReference = new WeakReference<>(myOwnClassLoader); + assertNotNull(myOwnClassLoaderWeakReference.get()); + objectStreamClass_MemoryLeakExample = null; + myOwnClassLoader = null; + loadClass = null; + con = null; + assertNotNull(myOwnClassLoaderWeakReference.get()); + + ForceGC gc = new ForceGC(); + assertTrue(gc.await(() -> myOwnClassLoaderWeakReference.get() == null)); + } +} + +class ObjectStreamClass_MemoryLeakExample { + private static final ObjectStreamField[] fields = ObjectStreamClass.lookup(TestClass.class).getFields(); + public ObjectStreamClass_MemoryLeakExample() { + } + + @Override + public String toString() { + return Arrays.toString(fields); + } +} + +class TestClassLoader extends ClassLoader { + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (name.equals("TestClass") || name.equals("ObjectStreamClass_MemoryLeakExample")) { + byte[] bt = loadClassData(name); + return defineClass(name, bt, 0, bt.length); + } else { + return super.loadClass(name); + } + } + + private static byte[] loadClassData(String className) { + ByteArrayOutputStream byteSt = new ByteArrayOutputStream(); + try (InputStream is = TestClassLoader.class.getClassLoader().getResourceAsStream(className.replace(".", "/") + ".class")) { + int len = 0; + while ((len = is.read()) != -1) { + byteSt.write(len); + } + } catch (java.io.IOException e) { + e.printStackTrace(); + } + return byteSt.toByteArray(); + } +} + +class TestClass implements Serializable { + public String x; +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java openjdk-17-17.0.4+8/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java --- openjdk-17-17.0.3+7/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/io/Serializable/serialFilter/GlobalFilterTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -53,18 +53,6 @@ * * @summary Test Global Filters */ - -/* @test - * @bug 8261160 - * @summary Add a deserialization JFR event - * @build GlobalFilterTest SerialFilterTest - * @requires vm.hasJFR - * @run testng/othervm/policy=security.policy - * -XX:StartFlightRecording:name=DeserializationEvent,dumponexit=true - * -Djava.security.properties=${test.src}/java.security-extra1 - * -Djava.security.debug=properties GlobalFilterTest - */ - @Test public class GlobalFilterTest { private static final String serialPropName = "jdk.serialFilter"; diff -Nru openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/m1/p/Main.java openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/m1/p/Main.java --- openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/m1/p/Main.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/m1/p/Main.java 2022-07-14 08:05:38.000000000 +0000 @@ -25,6 +25,6 @@ public class Main { public static void main(String[] args) { - q.Hello.hello(); + q.r.Hello.hello(); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/m2/module-info.java openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/m2/module-info.java --- openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/m2/module-info.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/m2/module-info.java 2022-07-14 08:05:38.000000000 +0000 @@ -22,5 +22,5 @@ */ module m2 { - exports q; + exports q.r; } diff -Nru openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/m2/q/Hello.java openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/m2/q/Hello.java --- openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/m2/q/Hello.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/m2/q/Hello.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * 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 q; - -public class Hello { - public static void hello() { - System.out.println("hello"); - } -} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/m2/q/r/Hello.java openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/m2/q/r/Hello.java --- openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/m2/q/r/Hello.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/m2/q/r/Hello.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 q.r; + +public class Hello { + public static void hello() { + System.out.println("hello"); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/ModulesInCustomFileSystem.java openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/ModulesInCustomFileSystem.java --- openjdk-17-17.0.3+7/test/jdk/java/lang/module/customfs/ModulesInCustomFileSystem.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/lang/module/customfs/ModulesInCustomFileSystem.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * 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,6 +23,7 @@ /** * @test + * @bug 8178380 8282444 * @modules jdk.zipfs * @library /test/lib * @build ModulesInCustomFileSystem m1/* m2/* diff -Nru openjdk-17-17.0.3+7/test/jdk/java/lang/ProcessBuilder/ArgCheck.java openjdk-17-17.0.4+8/test/jdk/java/lang/ProcessBuilder/ArgCheck.java --- openjdk-17-17.0.3+7/test/jdk/java/lang/ProcessBuilder/ArgCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/lang/ProcessBuilder/ArgCheck.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8282008 + * @requires (os.family == "windows") + * @run main/othervm ArgCheck + * @summary Check invocation of exe and non-exe programs using ProcessBuilder + * and arguments with spaces, backslashes, and simple quoting. + */ + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Class to check invocation of java, .cmd, and vbs scripts with arguments and various quote cases. + * Can be run standalone to compare results with other Java versions. + */ +public class ArgCheck { + + private static final Path SRC_DIR = Paths.get(System.getProperty("test.src", ".")); + private static final Path WORK_DIR = Paths.get(System.getProperty("user.dir", ".")); + private static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", ".")); + + private static final String ECHO_CMD_PATH = WORK_DIR.resolve("EchoArguments.cmd").toString(); + private static final String ECHO_VBS_PATH = WORK_DIR.resolve("EchoArguments.vbs").toString(); + + // Test argument containing both a space and a trailing backslash + // Depending on the mode the final backslash may act as an escape that may turn an added quote to a literal quote + private static final String SPACE_AND_BACKSLASH = "SPACE AND BACKSLASH\\"; + private static final char DOUBLE_QUOTE = '"'; + private static final char BACKSLASH = '\\'; + + private static final String AMBIGUOUS_PROP_NAME = "jdk.lang.Process.allowAmbiguousCommands"; + private static final String AMBIGUOUS_PROP_VALUE = System.getProperty(AMBIGUOUS_PROP_NAME); + private static final Boolean AMBIGUOUS_PROP_BOOLEAN = AMBIGUOUS_PROP_VALUE == null ? null : + Boolean.valueOf(!"false".equals(AMBIGUOUS_PROP_VALUE)); + + private static final List ECHO_JAVA_ARGS = Arrays.asList("java", "-classpath", TEST_CLASSES.toString(), "ArgCheck"); + private static final List ECHO_CMD_ARGS = Arrays.asList(ECHO_CMD_PATH); + private static final List ECHO_VBS_ARGS = Arrays.asList("CScript", "/b", ECHO_VBS_PATH); + + /** + * If zero arguments are supplied, run the test cases, by launching each as a child process. + * If there are arguments, then this is a child Java process that prints each argument to stdout. + * The test can be run manually with -Djdk.lang.Process.allowAmbiguousCommands={"true", "false", ""} + * to run a matching subset of the tests. + */ + public static void main(String[] args) throws IOException { + if (args.length > 0) { + // Echo supplied arguments and exit + for (String arg : args) + System.out.println(arg); + return; + } + + System.out.println("Java Version: " + System.getProperty("java.version")); + + createFiles(); + + int errors = 0; + int success = 0; + int skipped = 0; + + for (CMD cmd : CASES) { + // If System property jdk.lang.process.allowAmbiguousCommands matches the case, test it + // If undefined, test them all + if (AMBIGUOUS_PROP_BOOLEAN == null || + AMBIGUOUS_PROP_BOOLEAN.booleanValue() == cmd.allowAmbiguous) { + try { + testCommand(cmd); + success++; + } catch (Exception ex) { + ex.printStackTrace(); + errors++; + } + } else { + // skip unmatched cases + skipped++; + } + } + if (skipped > 0) { + System.out.printf("%d cases skipped, they did not match the tests with jdk.lang.Process.allowAmbiguousCommands: %s%n", + skipped, AMBIGUOUS_PROP_BOOLEAN); + } + System.out.printf("\nSuccess: %d, errors: %d%n", success, errors); + if (errors > 0) { + throw new RuntimeException("Errors: " + errors); + } + } + + /** + * A CMD holds the parameters and the expected result of invoking a process with the parameters. + */ + static class CMD { + /** + * Construct a test case. + * @param allowAmbiguous true/false to set property jdk.lang.Process.allowAmbiguousCommands + * @param command list of command parameters to invoke the executable or script + * @param arguments list of arguments (appended to the command) + * @param expected expected lines of output from invoked command + */ + CMD(boolean allowAmbiguous, List command, List arguments, List expected) { + this.allowAmbiguous = allowAmbiguous; + this.command = command; + this.arguments = arguments; + this.expected = expected; + } + + final boolean allowAmbiguous; + final List command; + final List arguments; + final List expected; + } + + /** + * List of cases with the command, arguments, allowAmbiguous setting, and the expected results + */ + static final List CASES = Arrays.asList( + + // allowAmbiguousCommands = false, without application supplied double-quotes. + // The space in the argument requires it to be quoted, the final backslash + // must not be allowed to turn the quote that is added into a literal + // instead of closing the quote. + new CMD(false, + ECHO_JAVA_ARGS, + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_1"), + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_1")), + new CMD(false, + ECHO_CMD_ARGS, + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_2"), + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_2")), + new CMD(false, + ECHO_VBS_ARGS, + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_3"), + Arrays.asList(SPACE_AND_BACKSLASH + BACKSLASH, "ARG_3")), + + // allowAmbiguousCommands = false, WITH application supplied double-quotes around the argument + // The argument has surrounding quotes so does not need further quoting. + // However, for exe commands, the final backslash must not be allowed to turn the quote + // into a literal instead of closing the quote. + new CMD(false, + ECHO_JAVA_ARGS, + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_11"), + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_11")), + new CMD(false, + ECHO_CMD_ARGS, + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_12"), + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_12")), + new CMD(false, + ECHO_VBS_ARGS, + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_13"), + Arrays.asList(SPACE_AND_BACKSLASH + BACKSLASH, "ARG_13")), + + // Legacy mode tests; allowAmbiguousCommands = true; no application supplied quotes + // The space in the argument requires it to be quoted, the final backslash + // must not be allowed to turn the quote that is added into a literal + // instead of closing the quote. + new CMD(true, + ECHO_JAVA_ARGS, + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_21"), + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_21")), + new CMD(true, + ECHO_CMD_ARGS, + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_22"), + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + BACKSLASH + DOUBLE_QUOTE, "ARG_22")), + new CMD(true, + ECHO_VBS_ARGS, + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_23"), + Arrays.asList(SPACE_AND_BACKSLASH + BACKSLASH, "ARG_23")), + + // allowAmbiguousCommands = true, WITH application supplied double-quotes around the argument + // The argument has surrounding quotes so does not need further quoting. + // The backslash before the final quote is ignored and is interpreted differently for each command. + new CMD(true, + ECHO_JAVA_ARGS, + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_31"), + Arrays.asList("SPACE AND BACKSLASH\" ARG_31")), + new CMD(true, + ECHO_CMD_ARGS, + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_32"), + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_32")), + new CMD(true, + ECHO_VBS_ARGS, + Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_33"), + Arrays.asList(SPACE_AND_BACKSLASH, "ARG_33")) + ); + + /** + * Common function to Invoke a process with the commands and check the result. + * + * @param cmd a CMD test case with arguments, allowAmbiguousCommands mode, and expected output + */ + private static void testCommand(CMD cmd) throws Exception { + System.setProperty(AMBIGUOUS_PROP_NAME, Boolean.toString(cmd.allowAmbiguous)); + List actual = null; + List arguments = new ArrayList<>(cmd.command); + arguments.addAll(cmd.arguments); + try { + // Launch the process and wait for termination + ProcessBuilder pb = new ProcessBuilder(arguments); + Process process = pb.start(); + try (InputStream is = process.getInputStream()) { + String str = readAllBytesAsString(is); + str = str.replace("\r", ""); + actual = Arrays.asList(str.split("\n")); + } catch (IOException ioe) { + throw new RuntimeException(ioe.getMessage(), ioe); + } + int exitCode = process.waitFor(); + if (exitCode != 0) { + actual = new ArrayList(actual); + actual.add("Exit code: " + exitCode); + } + } catch (IOException ioe) { + actual = Arrays.asList(ioe.getMessage().replace(arguments.get(0), "CMD")); + } catch (Exception ex) { + actual = Arrays.asList(ex.getMessage()); // Use exception message as output + } + if (!Objects.equals(actual, cmd.expected)) { + System.out.println("Invoking(" + cmd.allowAmbiguous + "): " + arguments); + if (actual.size() != cmd.expected.size()) { + System.out.println("Args Length: actual: " + actual.size() + " expected: " + cmd.expected.size()); + } + System.out.println("Actual: " + actual); + System.out.println("Expected: " + cmd.expected); + System.out.println(); + throw new RuntimeException("Unexpected output"); + } + } + + /** + * Private method to readAllBytes as a String. + * (InputStream.readAllBytes is not supported by the JDK until 9) + * @param is an InputStream + * @return a String with the contents + * @throws IOException if an error occurs + */ + private static String readAllBytesAsString(InputStream is) throws IOException { + final int BUF_SIZE = 8192; + byte[] bytes = new byte[BUF_SIZE]; + int off = 0; + int len; + while ((len = is.read(bytes, off, bytes.length - off)) > 0) { + off += len; + if (off >= bytes.length) { + // no space in buffer, reallocate larger + bytes = Arrays.copyOf(bytes, bytes.length + BUF_SIZE); + } + } + return new String(bytes, 0, off, Charset.defaultCharset()); + } + + /** + * Initialize .cmd and .vbs scripts. + * + * @throws Error if an exception occurs + */ + private static void createFiles() throws IOException { + Files.write(Paths.get(ECHO_CMD_PATH), EchoArgumentsCmd.getBytes(StandardCharsets.UTF_8)); + Files.write(Paths.get(ECHO_VBS_PATH), EchoArgumentsVbs.getBytes(StandardCharsets.UTF_8)); + } + + /** + * Self contained .cmd to echo each argument on a separate line. + */ + static final String EchoArgumentsCmd = "@echo off\n" + + "set p1=\n" + + "set p2=\n" + + "\n" + + "if not [%1]==[] set p1=%1\n" + + "if not [%2]==[] set p2=%2\n" + + "if not [%3]==[] set p3=%3\n" + + "if defined p1 echo %p1%\n" + + "if defined p2 echo %p2%\n" + + "if defined p3 echo %p3%\n" + + "exit /b 0\n"; + + + /** + * Self contained .vbs to echo each argument on a separate line. + */ + static final String EchoArgumentsVbs = "Option Explicit\n" + + "Dim arg\n" + + "for each arg in WScript.Arguments\n" + + " WScript.StdOut.WriteLine(arg)\n" + + "Next\n"; +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/lang/RuntimeTests/exec/ExecWithDir.java openjdk-17-17.0.4+8/test/jdk/java/lang/RuntimeTests/exec/ExecWithDir.java --- openjdk-17-17.0.3+7/test/jdk/java/lang/RuntimeTests/exec/ExecWithDir.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/lang/RuntimeTests/exec/ExecWithDir.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. - * 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 4750978 - * @run main/othervm/timeout=300 ExecWithDir - * @summary Ensure that we can fork-and-exec repeatedly when a new working - * directory is specified - */ - -import java.io.File; - -public class ExecWithDir { - - private static final int N = 500; - - public static void main(String args[]) throws Exception { - if (! UnixCommands.isUnix) { - System.out.println("For UNIX only"); - return; - } - UnixCommands.ensureCommandsAvailable("true"); - - final String trueCmd = UnixCommands.findCommand("true"); - File dir = new File("."); - for (int i = 1; i <= N; i++) { - System.out.print(i); - System.out.print(" e"); - Process p = Runtime.getRuntime().exec(trueCmd, null, dir); - System.out.print('w'); - int s = p.waitFor(); - System.out.println("x " + s); - if (s != 0) throw new Error("Unexpected return code " + s); - - // Avoid "Too many open files" - p.getInputStream().close(); - p.getOutputStream().close(); - p.getErrorStream().close(); - } - } -} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBodyGet.java openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBodyGet.java --- openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBodyGet.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBodyGet.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8216498 + * @summary Tests Exception detail message when too few response bytes are + * received before a socket exception or eof. + * @library /test/lib + * @build jdk.test.lib.net.SimpleSSLContext ShortResponseBody ShortResponseBodyGet + * @run testng/othervm + * -Djdk.httpclient.HttpClient.log=headers,errors,channel + * ShortResponseBodyGet + */ + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.ExecutionException; +import org.testng.annotations.Test; +import static java.lang.System.out; +import static java.net.http.HttpResponse.BodyHandlers.ofString; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +public class ShortResponseBodyGet extends ShortResponseBody { + + @Test(dataProvider = "uris") + void testSynchronousGET(String urlp, String expectedMsg, boolean sameClient) + throws Exception + { + checkSkip(); + out.print("---\n"); + HttpClient client = null; + for (int i=0; i< ITERATION_COUNT; i++) { + String url = uniqueURL(urlp); + if (client == null) + client = newHttpClient(sameClient); + HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build(); + out.println("Request: " + request); + try { + HttpResponse response = client.send(request, ofString()); + String body = response.body(); + out.println(response + ": " + body); + fail("UNEXPECTED RESPONSE: " + response); + } catch (IOException ioe) { + out.println("Caught expected exception:" + ioe); + assertExpectedMessage(request, ioe, expectedMsg); + // synchronous API must have the send method on the stack + assertSendMethodOnStack(ioe); + assertNoConnectionExpiredException(ioe); + } + } + } + + @Test(dataProvider = "uris") + void testAsynchronousGET(String urlp, String expectedMsg, boolean sameClient) + throws Exception + { + checkSkip(); + out.print("---\n"); + HttpClient client = null; + for (int i=0; i< ITERATION_COUNT; i++) { + String url = uniqueURL(urlp); + if (client == null) + client = newHttpClient(sameClient); + HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build(); + out.println("Request: " + request); + try { + HttpResponse response = client.sendAsync(request, ofString()).get(); + String body = response.body(); + out.println(response + ": " + body); + fail("UNEXPECTED RESPONSE: " + response); + } catch (ExecutionException ee) { + if (ee.getCause() instanceof IOException) { + IOException ioe = (IOException) ee.getCause(); + out.println("Caught expected exception:" + ioe); + assertExpectedMessage(request, ioe, expectedMsg); + assertNoConnectionExpiredException(ioe); + } else { + throw ee; + } + } + } + } + +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBody.java openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBody.java --- openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBody.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBody.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * 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,17 +21,6 @@ * questions. */ -/* - * @test - * @bug 8216498 - * @summary Tests Exception detail message when too few response bytes are - * received before a socket exception or eof. - * @library /test/lib - * @build jdk.test.lib.net.SimpleSSLContext - * @run testng/othervm - * -Djdk.httpclient.HttpClient.log=headers,errors,channel - * ShortResponseBody - */ import java.io.IOException; import java.io.InputStream; @@ -44,12 +33,10 @@ import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; -import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -81,7 +68,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; -public class ShortResponseBody { +public abstract class ShortResponseBody { Server closeImmediatelyServer; Server closeImmediatelyHttpsServer; @@ -98,10 +85,17 @@ SSLContext sslContext; SSLParameters sslParameters; + static final long PAUSE_FOR_GC = 5; // 5ms to let gc work + static final long PAUSE_FOR_PEER = 5; // 5ms to let server react + static final String EXPECTED_RESPONSE_BODY = "

    Heading

    Some Text

    "; - final static AtomicLong ids = new AtomicLong(); + // A request number used to replace %reqnb% in URLs with a unique + // number for better log analysis + static final AtomicLong reqnb = new AtomicLong(); + + static final AtomicLong ids = new AtomicLong(); final ThreadFactory factory = new ThreadFactory() { @Override public Thread newThread(Runnable r) { @@ -125,6 +119,12 @@ @BeforeMethod void beforeMethod(ITestContext context) { + System.gc(); + try { + Thread.sleep(PAUSE_FOR_GC); + } catch (InterruptedException x) { + + } if (context.getFailedTests().size() > 0) { if (skiptests.get() == null) { SkipException skip = new SkipException("some tests failed"); @@ -162,10 +162,16 @@ }; } + public static String uniqueURL(String url) { + return url.replace("%reqnb%", String.valueOf(reqnb.incrementAndGet())); + } + @Test(dataProvider = "sanity") void sanity(String url) throws Exception { HttpClient client = newHttpClient(); + url = uniqueURL(url); HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build(); + out.println("Request: " + request); HttpResponse response = client.send(request, ofString()); String body = response.body(); assertEquals(body, EXPECTED_RESPONSE_BODY); @@ -263,59 +269,16 @@ .build(); } - @Test(dataProvider = "uris") - void testSynchronousGET(String url, String expectedMsg, boolean sameClient) - throws Exception - { - checkSkip(); - out.print("---\n"); - HttpClient client = null; - for (int i=0; i< ITERATION_COUNT; i++) { - if (!sameClient || client == null) - client = newHttpClient(); - HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build(); - try { - HttpResponse response = client.send(request, ofString()); - String body = response.body(); - out.println(response + ": " + body); - fail("UNEXPECTED RESPONSE: " + response); - } catch (IOException ioe) { - out.println("Caught expected exception:" + ioe); - assertExpectedMessage(request, ioe, expectedMsg); - // synchronous API must have the send method on the stack - assertSendMethodOnStack(ioe); - assertNoConnectionExpiredException(ioe); - } - } - } - - @Test(dataProvider = "uris") - void testAsynchronousGET(String url, String expectedMsg, boolean sameClient) - throws Exception - { - checkSkip(); - out.print("---\n"); - HttpClient client = null; - for (int i=0; i< ITERATION_COUNT; i++) { - if (!sameClient || client == null) - client = newHttpClient(); - HttpRequest request = HttpRequest.newBuilder(URI.create(url)).build(); - try { - HttpResponse response = client.sendAsync(request, ofString()).get(); - String body = response.body(); - out.println(response + ": " + body); - fail("UNEXPECTED RESPONSE: " + response); - } catch (ExecutionException ee) { - if (ee.getCause() instanceof IOException) { - IOException ioe = (IOException) ee.getCause(); - out.println("Caught expected exception:" + ioe); - assertExpectedMessage(request, ioe, expectedMsg); - assertNoConnectionExpiredException(ioe); - } else { - throw ee; - } + HttpClient sharedClient = null; + HttpClient newHttpClient(boolean shared) { + if (shared) { + HttpClient sharedClient = this.sharedClient; + if (sharedClient == null) { + sharedClient = this.sharedClient = newHttpClient(); } + return sharedClient; } + return newHttpClient(); } // can be used to prolong request body publication @@ -331,6 +294,11 @@ k16++; System.out.println("... 16K sent."); count = count % (16 * 1024); + try { + Thread.sleep(PAUSE_FOR_PEER); + } catch (InterruptedException x) { + // ignore + } } if (k16 > 128) { System.out.println("WARNING: InfiniteInputStream: " + @@ -353,6 +321,11 @@ k16++; System.out.println("... 16K sent."); count = count % (16 * 1024); + try { + Thread.sleep(PAUSE_FOR_PEER); + } catch (InterruptedException x) { + // ignore + } } if (k16 > 128) { System.out.println("WARNING: InfiniteInputStream: " + @@ -364,86 +337,6 @@ } } - // POST tests are racy in what may be received before writing may cause a - // broken pipe or reset exception, before all the received data can be read. - // Any message up to, and including, the "expected" error message can occur. - // Strictly ordered list, in order of possible occurrence. - static final List MSGS_ORDER = - List.of("no bytes", "status line", "header"); - - - @Test(dataProvider = "uris") - void testSynchronousPOST(String url, String expectedMsg, boolean sameClient) - throws Exception - { - checkSkip(); - out.print("---\n"); - HttpClient client = null; - for (int i=0; i< ITERATION_COUNT; i++) { - if (!sameClient || client == null) - client = newHttpClient(); - HttpRequest request = HttpRequest.newBuilder(URI.create(url)) - .POST(BodyPublishers.ofInputStream(() -> new InfiniteInputStream())) - .build(); - try { - HttpResponse response = client.send(request, ofString()); - String body = response.body(); - out.println(response + ": " + body); - fail("UNEXPECTED RESPONSE: " + response); - } catch (IOException ioe) { - out.println("Caught expected exception:" + ioe); - - List expectedMessages = new ArrayList<>(); - expectedMessages.add(expectedMsg); - MSGS_ORDER.stream().takeWhile(s -> !s.equals(expectedMsg)) - .forEach(expectedMessages::add); - - assertExpectedMessage(request, ioe, expectedMessages); - // synchronous API must have the send method on the stack - assertSendMethodOnStack(ioe); - assertNoConnectionExpiredException(ioe); - } - } - } - - @Test(dataProvider = "uris") - void testAsynchronousPOST(String url, String expectedMsg, boolean sameClient) - throws Exception - { - checkSkip(); - out.print("---\n"); - HttpClient client = null; - for (int i=0; i< ITERATION_COUNT; i++) { - if (!sameClient || client == null) - client = newHttpClient(); - HttpRequest request = HttpRequest.newBuilder(URI.create(url)) - .POST(BodyPublishers.ofInputStream(() -> new InfiniteInputStream())) - .build(); - try { - HttpResponse response = client.sendAsync(request, ofString()).get(); - String body = response.body(); - out.println(response + ": " + body); - fail("UNEXPECTED RESPONSE: " + response); - } catch (ExecutionException ee) { - if (ee.getCause() instanceof IOException) { - IOException ioe = (IOException) ee.getCause(); - out.println("Caught expected exception:" + ioe); - - List expectedMessages = new ArrayList<>(); - expectedMessages.add(expectedMsg); - MSGS_ORDER.stream().takeWhile(s -> !s.equals(expectedMsg)) - .forEach(expectedMessages::add); - - assertExpectedMessage(request, ioe, expectedMessages); - assertNoConnectionExpiredException(ioe); - } else { - throw ee; - } - } - } - } - - void assertExpectedMessage(HttpRequest request, Throwable t, String expected) { if (request.uri().getScheme().equalsIgnoreCase("https") && (t instanceof SSLHandshakeException)) { @@ -758,27 +651,28 @@ closeImmediatelyServer = new PlainCloseImmediatelyServer(); httpURIClsImed = "http://" + serverAuthority(closeImmediatelyServer) - + "/http1/closeImmediately/foo"; + + "/http1/closeImmediately/req=%reqnb%/foo"; closeImmediatelyHttpsServer = new SSLCloseImmediatelyServer(); httpsURIClsImed = "https://" + serverAuthority(closeImmediatelyHttpsServer) - + "/https1/closeImmediately/foo"; + + "/https1/closeImmediately/req=%reqnb%/foo"; variableLengthServer = new PlainVariableLengthServer(); httpURIVarLen = "http://" + serverAuthority(variableLengthServer) - + "/http1/variable/bar"; + + "/http1/variable/req=%reqnb%/bar"; variableLengthHttpsServer = new SSLVariableLengthServer(); httpsURIVarLen = "https://" + serverAuthority(variableLengthHttpsServer) - + "/https1/variable/bar"; + + "/https1/variable/req=%reqnb%/bar"; fixedLengthServer = new FixedLengthServer(); httpURIFixLen = "http://" + serverAuthority(fixedLengthServer) - + "/http1/fixed/baz"; + + "/http1/fixed/req=%reqnb%/baz"; } @AfterTest public void teardown() throws Exception { + if (sharedClient != null) sharedClient = null; closeImmediatelyServer.close(); closeImmediatelyHttpsServer.close(); variableLengthServer.close(); diff -Nru openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBodyPost.java openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBodyPost.java --- openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBodyPost.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBodyPost.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8216498 + * @summary Tests Exception detail message when too few response bytes are + * received before a socket exception or eof. + * @library /test/lib + * @build jdk.test.lib.net.SimpleSSLContext ShortResponseBody ShortResponseBodyPost + * @run testng/othervm + * -Djdk.httpclient.HttpClient.log=headers,errors,channel + * -Djdk.internal.httpclient.debug=true + * ShortResponseBodyPost + */ + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import org.testng.annotations.Test; +import static java.lang.System.out; +import static java.net.http.HttpResponse.BodyHandlers.ofString; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; +public class ShortResponseBodyPost extends ShortResponseBody { + + // POST tests are racy in what may be received before writing may cause a + // broken pipe or reset exception, before all the received data can be read. + // Any message up to, and including, the "expected" error message can occur. + // Strictly ordered list, in order of possible occurrence. + static final List MSGS_ORDER = + List.of("no bytes", "status line", "header"); + + + @Test(dataProvider = "uris") + void testSynchronousPOST(String urlp, String expectedMsg, boolean sameClient) + throws Exception + { + checkSkip(); + out.print("---\n"); + HttpClient client = null; + for (int i=0; i< ITERATION_COUNT; i++) { + String url = uniqueURL(urlp); + if (client == null) + client = newHttpClient(sameClient); + HttpRequest request = HttpRequest.newBuilder(URI.create(url)) + .POST(BodyPublishers.ofInputStream(() -> new InfiniteInputStream())) + .build(); + out.println("Request: " + request); + try { + HttpResponse response = client.send(request, ofString()); + String body = response.body(); + out.println(response + ": " + body); + fail("UNEXPECTED RESPONSE: " + response); + } catch (IOException ioe) { + out.println("Caught expected exception:" + ioe); + + List expectedMessages = new ArrayList<>(); + expectedMessages.add(expectedMsg); + MSGS_ORDER.stream().takeWhile(s -> !s.equals(expectedMsg)) + .forEach(expectedMessages::add); + + assertExpectedMessage(request, ioe, expectedMessages); + // synchronous API must have the send method on the stack + assertSendMethodOnStack(ioe); + assertNoConnectionExpiredException(ioe); + } + } + } + + @Test(dataProvider = "uris") + void testAsynchronousPOST(String urlp, String expectedMsg, boolean sameClient) + throws Exception + { + checkSkip(); + out.print("---\n"); + HttpClient client = null; + for (int i=0; i< ITERATION_COUNT; i++) { + String url = uniqueURL(urlp); + if (client == null) + client = newHttpClient(sameClient); + HttpRequest request = HttpRequest.newBuilder(URI.create(url)) + .POST(BodyPublishers.ofInputStream(() -> new InfiniteInputStream())) + .build(); + out.println("Request: " + request); + try { + HttpResponse response = client.sendAsync(request, ofString()).get(); + String body = response.body(); + out.println(response + ": " + body); + fail("UNEXPECTED RESPONSE: " + response); + } catch (ExecutionException ee) { + if (ee.getCause() instanceof IOException) { + IOException ioe = (IOException) ee.getCause(); + out.println("Caught expected exception:" + ioe); + + List expectedMessages = new ArrayList<>(); + expectedMessages.add(expectedMsg); + MSGS_ORDER.stream().takeWhile(s -> !s.equals(expectedMsg)) + .forEach(expectedMessages::add); + + assertExpectedMessage(request, ioe, expectedMessages); + assertNoConnectionExpiredException(ioe); + } else { + throw ee; + } + } + } + } + +} + diff -Nru openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBodyPostWithRetry.java openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBodyPostWithRetry.java --- openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBodyPostWithRetry.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBodyPostWithRetry.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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 + * @summary Run of ShortResponseBodyPost with -Djdk.httpclient.enableAllMethodRetry + * @library /test/lib + * @build jdk.test.lib.net.SimpleSSLContext + * @build ShortResponseBody ShortResponseBodyPost + * @run testng/othervm + * -Djdk.httpclient.HttpClient.log=headers,errors,channel + * -Djdk.httpclient.enableAllMethodRetry + * -Djdk.internal.httpclient.debug=true + * ShortResponseBodyPost + */ diff -Nru openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBodyWithRetry.java openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBodyWithRetry.java --- openjdk-17-17.0.3+7/test/jdk/java/net/httpclient/ShortResponseBodyWithRetry.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/net/httpclient/ShortResponseBodyWithRetry.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 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 - * @summary Run of ShortResponseBody with -Djdk.httpclient.enableAllMethodRetry - * @library /test/lib - * @build jdk.test.lib.net.SimpleSSLContext - * @build ShortResponseBody - * @run testng/othervm - * -Djdk.httpclient.HttpClient.log=headers,errors,channel - * -Djdk.httpclient.enableAllMethodRetry - * ShortResponseBody - */ diff -Nru openjdk-17-17.0.3+7/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java openjdk-17-17.0.4+8/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java --- openjdk-17-17.0.3+7/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * 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,7 +22,7 @@ */ /* @test - * @bug 7132924 + * @bug 7132924 8285515 * @library /test/lib * @key intermittent * @summary Test DatagramChannel.disconnect when DatagramChannel is connected to an IPv4 socket diff -Nru openjdk-17-17.0.3+7/test/jdk/java/nio/file/Files/InterruptCopy.java openjdk-17-17.0.4+8/test/jdk/java/nio/file/Files/InterruptCopy.java --- openjdk-17-17.0.3+7/test/jdk/java/nio/file/Files/InterruptCopy.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/nio/file/Files/InterruptCopy.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. * 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,16 +28,24 @@ * @library .. */ -import java.nio.file.*; -import java.io.*; -import java.util.concurrent.*; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.FileStore; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; import com.sun.nio.file.ExtendedCopyOption; public class InterruptCopy { - private static final long FILE_SIZE_TO_COPY = 512L * 1024L * 1024L; - private static final int DELAY_IN_MS = 500; - private static final int DURATION_MAX_IN_MS = 5000; + private static final long FILE_SIZE_TO_COPY = 1024L * 1024L * 1024L; + private static final int INTERRUPT_DELAY_IN_MS = 50; + private static final int CANCEL_DELAY_IN_MS = 10; public static void main(String[] args) throws Exception { Path dir = TestUtil.createTemporaryDirectory(); @@ -74,46 +82,83 @@ ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor(); + try { - // copy source to target in main thread, interrupting it after a delay + // copy source to target in main thread, interrupting it + // after a delay final Thread me = Thread.currentThread(); - Future wakeup = pool.schedule(new Runnable() { + final CountDownLatch interruptLatch = new CountDownLatch(1); + Future wakeup = pool.submit(new Runnable() { public void run() { + try { + interruptLatch.await(); + Thread.sleep(INTERRUPT_DELAY_IN_MS); + } catch (InterruptedException ignore) { + } + System.out.printf("Interrupting at %d ms...%n", + System.currentTimeMillis()); me.interrupt(); - }}, DELAY_IN_MS, TimeUnit.MILLISECONDS); - System.out.println("Copying file..."); + } + }); try { - long start = System.currentTimeMillis(); + interruptLatch.countDown(); + long theBeginning = System.currentTimeMillis(); + System.out.printf("Copying file at %d ms...%n", theBeginning); Files.copy(source, target, ExtendedCopyOption.INTERRUPTIBLE); - long duration = System.currentTimeMillis() - start; - if (duration > DURATION_MAX_IN_MS) - throw new RuntimeException("Copy was not interrupted"); + long theEnd = System.currentTimeMillis(); + System.out.printf("Done copying at %d ms...%n", theEnd); + long duration = theEnd - theBeginning; + + // If the copy was interrupted the target file should have been + // deleted, so if the file does not exist, then the copy must + // have been interrupted without throwing an exception; if the + // file exists, then the copy finished before being interrupted + // so not throwing an exception is not considered a failure + if (Files.notExists(target)) + throw new RuntimeException("Copy was not interrupted in " + + duration + " ms"); } catch (IOException e) { boolean interrupted = Thread.interrupted(); if (!interrupted) throw new RuntimeException("Interrupt status was not set"); - System.out.println("Copy failed (this is expected)"); + System.out.println("Copy failed (this is expected)."); } try { wakeup.get(); } catch (InterruptedException ignore) { } Thread.interrupted(); - // copy source to target via task in thread pool, interrupting it after - // a delay using cancel(true) + // copy source to target via task in thread pool, interrupting it + // after a delay using cancel(true) + CountDownLatch cancelLatch = new CountDownLatch(1); Future result = pool.submit(new Callable() { public Void call() throws IOException { - System.out.println("Copying file..."); + cancelLatch.countDown(); + System.out.printf("Copying file at %d ms...%n", + System.currentTimeMillis()); Files.copy(source, target, ExtendedCopyOption.INTERRUPTIBLE, StandardCopyOption.REPLACE_EXISTING); + System.out.printf("Done copying at %d ms...%n", + System.currentTimeMillis()); return null; } }); - Thread.sleep(DELAY_IN_MS); - boolean cancelled = result.cancel(true); - if (!cancelled) + try { + cancelLatch.await(); + Thread.sleep(CANCEL_DELAY_IN_MS); + } catch (InterruptedException ignore) { + } + if (result.isDone()) + throw new RuntimeException("Copy finished before cancellation"); + System.out.printf("Cancelling at %d ms...%n", + System.currentTimeMillis()); + boolean cancelled = result.cancel(true); + if (cancelled) + System.out.println("Copy cancelled."); + else { result.get(); - System.out.println("Copy cancelled."); + throw new RuntimeException("Copy was not cancelled"); + } } finally { pool.shutdown(); } diff -Nru openjdk-17-17.0.3+7/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java openjdk-17-17.0.4+8/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java --- openjdk-17-17.0.3+7/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8282929 + * @summary Verifies that toLocalizedPattern() method correctly returns + * monetary symbols in a currency formatter + * @run testng ToLocalizedPatternTest + */ + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.Test; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +@Test +public class ToLocalizedPatternTest { + private static final char MONETARY_GROUPING = 'g'; + private static final char MONETARY_DECIMAL = 'd'; + + public void testToLocalizedPattern() { + var dfs = new DecimalFormatSymbols(Locale.US); + + // Customize the decimal format symbols + dfs.setMonetaryGroupingSeparator(MONETARY_GROUPING); + dfs.setMonetaryDecimalSeparator(MONETARY_DECIMAL); + + // create a currency formatter + var cf = (DecimalFormat)DecimalFormat.getCurrencyInstance(Locale.US); + cf.setDecimalFormatSymbols(dfs); + + // check + assertEquals(cf.toLocalizedPattern(), + cf.toPattern() + .replace(',', MONETARY_GROUPING) + .replace('.', MONETARY_DECIMAL)); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/util/Random/RandomExponentialTest.java openjdk-17-17.0.4+8/test/jdk/java/util/Random/RandomExponentialTest.java --- openjdk-17-17.0.3+7/test/jdk/java/util/Random/RandomExponentialTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/util/Random/RandomExponentialTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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; + +/** + * @test + * @summary Check that nextExponential() returns non-negative outcomes + * @bug 8284866 + * + * @key randomness + * @library /test/lib + * @build jdk.test.lib.RandomFactory + * @run main RandomExponentialTest + */ + +public class RandomExponentialTest { + + private static final int SAMPLES = 1_000_000_000; + + public static void main(String[] args) throws Exception { + var errCount = 0; + var errSample = Double.NaN; + var random = RandomFactory.getRandom(); + for (int i = 0; i < SAMPLES; i++) { + var expVal = random.nextExponential(); + if (!(expVal >= 0.0)) { + errCount += 1; + errSample = expVal; + } + } + if (errCount > 0) { + throw new RuntimeException("%d errors out of %d samples: e.g., %f" + .formatted(errCount, SAMPLES, errSample)); + } + } + +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/util/regex/GraphemeTest.java openjdk-17-17.0.4+8/test/jdk/java/util/regex/GraphemeTest.java --- openjdk-17-17.0.3+7/test/jdk/java/util/regex/GraphemeTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/util/regex/GraphemeTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * 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,23 +26,25 @@ * @bug 7071819 8221431 8239383 * @summary tests Unicode Extended Grapheme support * @library /lib/testlibrary/java/lang - * @run main GraphemeTest + * @run testng GraphemeTest */ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Scanner; -import java.util.regex.Pattern; -import java.util.regex.Matcher; + +import org.testng.annotations.Test; +import static org.testng.Assert.fail; public class GraphemeTest { - public static void main(String[] args) throws Throwable { + @Test + public static void testGraphemeBreakProperty() throws Throwable { testProps(UCDFiles.GRAPHEME_BREAK_PROPERTY); + } + + @Test + public static void testEmojiData() throws Throwable { testProps(UCDFiles.EMOJI_DATA); } @@ -78,7 +80,7 @@ System.out.printf("[%x] [%s][%d] -> [%s]%n", cp, expected, Character.getType(cp), types[getType(cp)]); else - throw new RuntimeException(String.format( + fail(String.format( "cp=[%x], expeced:[%s] result:[%s]%n", cp, expected, types[getType(cp)])); } diff -Nru openjdk-17-17.0.3+7/test/jdk/java/util/regex/NegativeArraySize.java openjdk-17-17.0.4+8/test/jdk/java/util/regex/NegativeArraySize.java --- openjdk-17-17.0.3+7/test/jdk/java/util/regex/NegativeArraySize.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/util/regex/NegativeArraySize.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * 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,18 +25,18 @@ * @test * @bug 8223174 * @summary Pattern.compile() can throw confusing NegativeArraySizeException - * @requires os.maxMemory >= 5g - * @run main/othervm NegativeArraySize -Xms5G -Xmx5G + * @requires os.maxMemory >= 5g & vm.bits == 64 + * @run testng/othervm -Xms5G -Xmx5G NegativeArraySize */ +import org.testng.annotations.Test; +import static org.testng.Assert.assertThrows; + import java.util.regex.Pattern; public class NegativeArraySize { - public static void main(String[] args) { - try { - Pattern.compile("\\Q" + "a".repeat(42 + Integer.MAX_VALUE / 3)); - throw new AssertionError("expected to throw"); - } catch (OutOfMemoryError expected) { - } + @Test + public static void testNegativeArraySize() { + assertThrows(OutOfMemoryError.class, () -> Pattern.compile("\\Q" + "a".repeat(42 + Integer.MAX_VALUE / 3))); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/java/util/regex/RegExTest.java openjdk-17-17.0.4+8/test/jdk/java/util/regex/RegExTest.java --- openjdk-17-17.0.3+7/test/jdk/java/util/regex/RegExTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/util/regex/RegExTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -24,7 +24,6 @@ /** * @test * @summary tests RegExp framework (use -Dseed=X to set PRNG seed) - * @author Mike McCloskey * @bug 4481568 4482696 4495089 4504687 4527731 4599621 4631553 4619345 * 4630911 4672616 4711773 4727935 4750573 4792284 4803197 4757029 4808962 * 4872664 4803179 4892980 4900747 4945394 4938995 4979006 4994840 4997476 @@ -36,23 +35,17 @@ * 8151481 4867170 7080302 6728861 6995635 6736245 4916384 6328855 6192895 * 6345469 6988218 6693451 7006761 8140212 8143282 8158482 8176029 8184706 * 8194667 8197462 8184692 8221431 8224789 8228352 8230829 8236034 8235812 - * 8216332 8214245 8237599 8241055 8247546 8258259 8037397 + * 8216332 8214245 8237599 8241055 8247546 8258259 8037397 8269753 * * @library /test/lib * @library /lib/testlibrary/java/lang * @build jdk.test.lib.RandomFactory - * @run main RegExTest + * @author Mike McCloskey + * @run testng RegExTest * @key randomness */ -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStreamReader; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; +import java.io.*; import java.math.BigInteger; import java.nio.CharBuffer; import java.nio.file.Files; @@ -74,145 +67,34 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +import org.testng.annotations.Test; +import org.testng.Assert; + + import jdk.test.lib.RandomFactory; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertNotSame; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; +import static org.testng.Assert.expectThrows; + /** * This is a test class created to check the operation of * the Pattern and Matcher classes. */ public class RegExTest { - private static Random generator = RandomFactory.getRandom(); - private static boolean failure = false; - private static int failCount = 0; - private static String firstFailure = null; - - /** - * Main to interpret arguments and run several tests. - * - */ - public static void main(String[] args) throws Exception { - // Most of the tests are in a file - processFile("TestCases.txt"); - //processFile("PerlCases.txt"); - processFile("BMPTestCases.txt"); - processFile("SupplementaryTestCases.txt"); - - // These test many randomly generated char patterns - bm(); - slice(); - - // These are hard to put into the file - escapes(); - blankInput(); - - // Substitition tests on randomly generated sequences - globalSubstitute(); - stringbufferSubstitute(); - stringbuilderSubstitute(); - - substitutionBasher(); - substitutionBasher2(); - - // Canonical Equivalence - ceTest(); - - // Anchors - anchorTest(); - - // boolean match calls - matchesTest(); - lookingAtTest(); - - // Pattern API - patternMatchesTest(); - - // Misc - lookbehindTest(); - nullArgumentTest(); - backRefTest(); - groupCaptureTest(); - caretTest(); - charClassTest(); - emptyPatternTest(); - findIntTest(); - group0Test(); - longPatternTest(); - octalTest(); - ampersandTest(); - negationTest(); - splitTest(); - appendTest(); - caseFoldingTest(); - commentsTest(); - unixLinesTest(); - replaceFirstTest(); - gTest(); - zTest(); - serializeTest(); - reluctantRepetitionTest(); - multilineDollarTest(); - dollarAtEndTest(); - caretBetweenTerminatorsTest(); - // This RFE rejected in Tiger numOccurrencesTest(); - javaCharClassTest(); - nonCaptureRepetitionTest(); - notCapturedGroupCurlyMatchTest(); - escapedSegmentTest(); - literalPatternTest(); - literalReplacementTest(); - regionTest(); - toStringTest(); - negatedCharClassTest(); - findFromTest(); - boundsTest(); - unicodeWordBoundsTest(); - caretAtEndTest(); - wordSearchTest(); - hitEndTest(); - toMatchResultTest(); - toMatchResultTest2(); - surrogatesInClassTest(); - removeQEQuotingTest(); - namedGroupCaptureTest(); - nonBmpClassComplementTest(); - unicodePropertiesTest(); - unicodeHexNotationTest(); - unicodeClassesTest(); - unicodeCharacterNameTest(); - horizontalAndVerticalWSTest(); - linebreakTest(); - branchTest(); - groupCurlyNotFoundSuppTest(); - groupCurlyBackoffTest(); - patternAsPredicate(); - patternAsMatchPredicate(); - invalidFlags(); - embeddedFlags(); - grapheme(); - expoBacktracking(); - invalidGroupName(); - illegalRepetitionRange(); - surrogatePairWithCanonEq(); - lineBreakWithQuantifier(); - caseInsensitivePMatch(); - surrogatePairOverlapRegion(); - droppedClassesWithIntersection(); - - - if (failure) { - throw new - RuntimeException("RegExTest failed, 1st failure: " + - firstFailure); - } else { - System.err.println("OKAY: All tests passed."); - } - } + private static final Random generator = RandomFactory.getRandom(); // Utility functions private static String getRandomAlphaString(int length) { - StringBuffer buf = new StringBuffer(length); + + StringBuilder buf = new StringBuilder(length); for (int i=0; i 0) { - failure = true; + private static void check(Pattern p, String s, String g, String expected) { + Matcher m = p.matcher(s); + m.find(); + assertFalse(!m.group(g).equals(expected) || + s.charAt(m.start(g)) != expected.charAt(0) || + s.charAt(m.end(g) - 1) != expected.charAt(expected.length() - 1)); + } + private static void checkReplaceFirst(String p, String s, String r, String expected) + { + assertEquals(expected, Pattern.compile(p).matcher(s).replaceFirst(r)); + } - if (firstFailure == null) { - firstFailure = testName; - } - } + private static void checkReplaceAll(String p, String s, String r, String expected) + { + assertEquals(expected, Pattern.compile(p).matcher(s).replaceAll(r)); + } - failCount = 0; + private static void checkExpectedFail(String p) { + assertThrows(PatternSyntaxException.class, () -> + Pattern.compile(p)); } /** @@ -296,9 +175,9 @@ * supplementary characters. This method does NOT fully take care * of the regex syntax. */ - private static String toSupplementaries(String s) { + public static String toSupplementaries(String s) { int length = s.length(); - StringBuffer sb = new StringBuffer(length * 2); + StringBuilder sb = new StringBuilder(length * 2); for (int i = 0; i < length; ) { char c = s.charAt(i++); @@ -325,153 +204,134 @@ } // Regular expression tests + //Following three tests execute from a file. + @Test + public static void processTestCases() throws IOException { + processFile("TestCases.txt"); + } - // This is for bug 6178785 - // Test if an expected NPE gets thrown when passing in a null argument - private static boolean check(Runnable test) { - try { - test.run(); - failCount++; - return false; - } catch (NullPointerException npe) { - return true; - } + @Test + public static void processBMPTestCases() throws IOException { + processFile("BMPTestCases.txt"); } - private static void nullArgumentTest() { - check(() -> Pattern.compile(null)); - check(() -> Pattern.matches(null, null)); - check(() -> Pattern.matches("xyz", null)); - check(() -> Pattern.quote(null)); - check(() -> Pattern.compile("xyz").split(null)); - check(() -> Pattern.compile("xyz").matcher(null)); + @Test + public static void processSupplementaryTestCases() throws IOException { + processFile("SupplementaryTestCases.txt"); + } + + + @Test + public static void nullArgumentTest() { + + assertThrows(NullPointerException.class, () -> Pattern.compile(null)); + assertThrows(NullPointerException.class, () -> Pattern.matches(null, null)); + assertThrows(NullPointerException.class, () -> Pattern.matches("xyz", null)); + assertThrows(NullPointerException.class, () -> Pattern.quote(null)); + assertThrows(NullPointerException.class, () -> Pattern.compile("xyz").split(null)); + assertThrows(NullPointerException.class, () -> Pattern.compile("xyz").matcher(null)); final Matcher m = Pattern.compile("xyz").matcher("xyz"); m.matches(); - check(() -> m.appendTail((StringBuffer) null)); - check(() -> m.appendTail((StringBuilder)null)); - check(() -> m.replaceAll((String) null)); - check(() -> m.replaceAll((Function)null)); - check(() -> m.replaceFirst((String)null)); - check(() -> m.replaceFirst((Function) null)); - check(() -> m.appendReplacement((StringBuffer)null, null)); - check(() -> m.appendReplacement((StringBuilder)null, null)); - check(() -> m.reset(null)); - check(() -> Matcher.quoteReplacement(null)); + assertThrows(NullPointerException.class, () -> m.appendTail((StringBuffer) null)); + assertThrows(NullPointerException.class, () -> m.appendTail((StringBuilder)null)); + assertThrows(NullPointerException.class, () -> m.replaceAll((String) null)); + assertThrows(NullPointerException.class, () -> m.replaceAll((Function)null)); + assertThrows(NullPointerException.class, () -> m.replaceFirst((String)null)); + assertThrows(NullPointerException.class, () -> m.replaceFirst((Function) null)); + assertThrows(NullPointerException.class, () -> m.appendReplacement((StringBuffer)null, null)); + assertThrows(NullPointerException.class, () -> m.appendReplacement((StringBuilder)null, null)); + assertThrows(NullPointerException.class, () -> m.reset(null)); + assertThrows(NullPointerException.class, () -> Matcher.quoteReplacement(null)); //check(() -> m.usePattern(null)); - report("Null Argument"); } // This is for bug6635133 // Test if surrogate pair in Unicode escapes can be handled correctly. - private static void surrogatesInClassTest() throws Exception { + @Test + public static void surrogatesInClassTest() { Pattern pattern = Pattern.compile("[\\ud834\\udd21-\\ud834\\udd24]"); Matcher matcher = pattern.matcher("\ud834\udd22"); - if (!matcher.find()) - failCount++; - report("Surrogate pair in Unicode escape"); + assertTrue(matcher.find(), "Surrogate pair in Unicode escape"); } // This is for bug6990617 // Test if Pattern.RemoveQEQuoting works correctly if the octal unicode // char encoding is only 2 or 3 digits instead of 4 and the first quoted // char is an octal digit. - private static void removeQEQuotingTest() throws Exception { + @Test + public static void removeQEQuotingTest() { Pattern pattern = Pattern.compile("\\011\\Q1sometext\\E\\011\\Q2sometext\\E"); Matcher matcher = pattern.matcher("\t1sometext\t2sometext"); - if (!matcher.find()) - failCount++; - report("Remove Q/E Quoting"); + assertTrue(matcher.find(), "Remove Q/E Quoting"); } // This is for bug 4988891 // Test toMatchResult to see that it is a copy of the Matcher // that is not affected by subsequent operations on the original - private static void toMatchResultTest() throws Exception { + @Test + public static void toMatchResultTest() { Pattern pattern = Pattern.compile("squid"); Matcher matcher = pattern.matcher( "agiantsquidofdestinyasmallsquidoffate"); matcher.find(); + int matcherStart1 = matcher.start(); MatchResult mr = matcher.toMatchResult(); - if (mr == matcher) - failCount++; + assertNotSame(mr, matcher, "Matcher toMatchResult is identical object"); + int resultStart1 = mr.start(); - if (matcherStart1 != resultStart1) - failCount++; + assertEquals(matcherStart1, resultStart1, "equal matchers don't have equal start indices"); matcher.find(); + int matcherStart2 = matcher.start(); int resultStart2 = mr.start(); - if (matcherStart2 == resultStart2) - failCount++; - if (resultStart1 != resultStart2) - failCount++; + assertNotEquals(matcherStart2, resultStart2, "Matcher2 and Result2 should not be equal"); + assertEquals(resultStart1, resultStart2, "Second match result should have the same state"); MatchResult mr2 = matcher.toMatchResult(); - if (mr == mr2) - failCount++; - if (mr2.start() != matcherStart2) - failCount++; - report("toMatchResult is a copy"); - } - - private static void checkExpectedISE(Runnable test) { - try { - test.run(); - failCount++; - } catch (IllegalStateException x) { - } catch (IndexOutOfBoundsException xx) { - failCount++; - } - } - - private static void checkExpectedIOOE(Runnable test) { - try { - test.run(); - failCount++; - } catch (IndexOutOfBoundsException x) {} + assertNotSame(mr, mr2, "Second Matcher copy should not be identical to the first."); + assertEquals(mr2.start(), matcherStart2, "mr2 index should equal matcher index"); } // This is for bug 8074678 // Test the result of toMatchResult throws ISE if no match is availble - private static void toMatchResultTest2() throws Exception { + @Test + public static void toMatchResultTest2() { Matcher matcher = Pattern.compile("nomatch").matcher("hello world"); matcher.find(); MatchResult mr = matcher.toMatchResult(); - checkExpectedISE(() -> mr.start()); - checkExpectedISE(() -> mr.start(2)); - checkExpectedISE(() -> mr.end()); - checkExpectedISE(() -> mr.end(2)); - checkExpectedISE(() -> mr.group()); - checkExpectedISE(() -> mr.group(2)); + assertThrows(IllegalStateException.class, mr::start); + assertThrows(IllegalStateException.class, () -> mr.start(2)); + assertThrows(IllegalStateException.class, mr::end); + assertThrows(IllegalStateException.class, () -> mr.end(2)); + assertThrows(IllegalStateException.class, mr::group); + assertThrows(IllegalStateException.class, () -> mr.group(2)); matcher = Pattern.compile("(match)").matcher("there is a match"); matcher.find(); MatchResult mr2 = matcher.toMatchResult(); - checkExpectedIOOE(() -> mr2.start(2)); - checkExpectedIOOE(() -> mr2.end(2)); - checkExpectedIOOE(() -> mr2.group(2)); - - report("toMatchResult2 appropriate exceptions"); + assertThrows(IndexOutOfBoundsException.class, () -> mr2.start(2)); + assertThrows(IndexOutOfBoundsException.class, () -> mr2.end(2)); + assertThrows(IndexOutOfBoundsException.class, () -> mr2.group(2)); } // This is for bug 5013885 // Must test a slice to see if it reports hitEnd correctly - private static void hitEndTest() throws Exception { + @Test + public static void hitEndTest() { // Basic test of Slice node Pattern p = Pattern.compile("^squidattack"); Matcher m = p.matcher("squack"); m.find(); - if (m.hitEnd()) - failCount++; + assertFalse(m.hitEnd(), "Matcher should not be at end of sequence"); m.reset("squid"); m.find(); - if (!m.hitEnd()) - failCount++; + assertTrue(m.hitEnd(), "Matcher should be at the end of sequence"); // Test Slice, SliceA and SliceU nodes for (int i=0; i<3; i++) { @@ -481,55 +341,47 @@ p = Pattern.compile("^abc", flags); m = p.matcher("ad"); m.find(); - if (m.hitEnd()) - failCount++; + assertFalse(m.hitEnd(), "Slice node test"); m.reset("ab"); m.find(); - if (!m.hitEnd()) - failCount++; + assertTrue(m.hitEnd(), "Slice node test"); } // Test Boyer-Moore node p = Pattern.compile("catattack"); m = p.matcher("attack"); m.find(); - if (!m.hitEnd()) - failCount++; + assertTrue(m.hitEnd(), "Boyer-Moore node test"); p = Pattern.compile("catattack"); m = p.matcher("attackattackattackcatatta"); m.find(); - if (!m.hitEnd()) - failCount++; + assertTrue(m.hitEnd(), "Boyer-More node test"); // 8184706: Matching u+0d at EOL against \R should hit-end p = Pattern.compile("...\\R"); m = p.matcher("cat" + (char)0x0a); m.find(); - if (m.hitEnd()) - failCount++; + assertFalse(m.hitEnd()); m = p.matcher("cat" + (char)0x0d); m.find(); - if (!m.hitEnd()) - failCount++; + assertTrue(m.hitEnd()); m = p.matcher("cat" + (char)0x0d + (char)0x0a); m.find(); - if (m.hitEnd()) - failCount++; - - report("hitEnd"); + assertFalse(m.hitEnd()); } // This is for bug 4997476 // It is weird code submitted by customer demonstrating a regression - private static void wordSearchTest() throws Exception { - String testString = new String("word1 word2 word3"); + @Test + public static void wordSearchTest() { + String testString = "word1 word2 word3"; Pattern p = Pattern.compile("\\b"); Matcher m = p.matcher(testString); int position = 0; - int start = 0; + int start; while (m.find(position)) { start = m.start(); if (start == testString.length()) @@ -541,14 +393,13 @@ } if (testString.substring(start, position).equals(" ")) continue; - if (!testString.substring(start, position-1).startsWith("word")) - failCount++; + assertTrue(testString.substring(start, position-1).startsWith("word")); } - report("Customer word search"); } // This is for bug 4994840 - private static void caretAtEndTest() throws Exception { + @Test + public static void caretAtEndTest() { // Problem only occurs with multiline patterns // containing a beginning-of-line caret "^" followed // by an expression that also matches the empty string. @@ -556,13 +407,13 @@ Matcher matcher = pattern.matcher("\r"); matcher.find(); matcher.find(); - report("Caret at end"); } // This test is for 4979006 // Check to see if word boundary construct properly handles unicode // non spacing marks - private static void unicodeWordBoundsTest() throws Exception { + @Test + public static void unicodeWordBoundsTest() { String spaces = " "; String wordChar = "a"; String nsm = "\u030a"; @@ -593,40 +444,35 @@ // SSNNSS input = spaces + nsm + nsm + spaces; matcher.reset(input); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); // SSN.BBN.SS input = spaces + nsm + wordChar + wordChar + nsm + spaces; twoFindIndexes(input, matcher, 3, 6); - - report("Unicode word boundary"); } private static void twoFindIndexes(String input, Matcher matcher, int a, - int b) throws Exception + int b) { matcher.reset(input); matcher.find(); - if (matcher.start() != a) - failCount++; + assertEquals(matcher.start(), a); matcher.find(); - if (matcher.start() != b) - failCount++; + assertEquals(matcher.start(), b); } // This test is for 6284152 - static void check(String regex, String input, String[] expected) { - List result = new ArrayList(); + private static void check(String regex, String input, String[] expected) { + List result = new ArrayList<>(); Pattern p = Pattern.compile(regex); Matcher m = p.matcher(input); while (m.find()) { result.add(m.group()); } - if (!Arrays.asList(expected).equals(result)) - failCount++; + assertEquals(Arrays.asList(expected), result); } - private static void lookbehindTest() throws Exception { + @Test + public static void lookbehindTest() { //Positive check("(?<=%.{0,5})foo\\d", "%foo1\n%bar foo2\n%bar foo3\n%blahblah foo4\nfoo5", @@ -659,162 +505,140 @@ new String[] {"fo\ud800\udc00o"}); check("(?]"); Matcher matcher = pattern.matcher("\u203A"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); + pattern = Pattern.compile("[^fr]"); matcher = pattern.matcher("a"); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); + matcher.reset("\u203A"); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); String s = "for"; - String result[] = s.split("[^fr]"); - if (!result[0].equals("f")) - failCount++; - if (!result[1].equals("r")) - failCount++; + String[] result = s.split("[^fr]"); + assertEquals(result[0], "f"); + assertEquals(result[1], "r"); s = "f\u203Ar"; result = s.split("[^fr]"); - if (!result[0].equals("f")) - failCount++; - if (!result[1].equals("r")) - failCount++; + assertEquals(result[0], "f"); + assertEquals(result[1], "r"); // Test adding to bits, subtracting a node, then adding to bits again pattern = Pattern.compile("[^f\u203Ar]"); matcher = pattern.matcher("a"); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); matcher.reset("f"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.reset("\u203A"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.reset("r"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.reset("\u203B"); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); // Test subtracting a node, adding to bits, subtracting again pattern = Pattern.compile("[^\u203Ar\u203B]"); matcher = pattern.matcher("a"); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); matcher.reset("\u203A"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.reset("r"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.reset("\u203B"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.reset("\u203C"); - if (!matcher.find()) - failCount++; - - report("Negated Character Class"); + assertTrue(matcher.find()); } // This test is for 4628291 - private static void toStringTest() throws Exception { + @Test + public static void toStringTest() { Pattern pattern = Pattern.compile("b+"); - if (pattern.toString() != "b+") - failCount++; + assertEquals(pattern.toString(), "b+"); Matcher matcher = pattern.matcher("aaabbbccc"); String matcherString = matcher.toString(); // unspecified matcher.find(); - matcherString = matcher.toString(); // unspecified + matcher.toString(); // unspecified matcher.region(0,3); - matcherString = matcher.toString(); // unspecified + matcher.toString(); // unspecified matcher.reset(); - matcherString = matcher.toString(); // unspecified - report("toString"); + matcher.toString(); // unspecified } // This test is for 4808962 - private static void literalPatternTest() throws Exception { + @Test + public static void literalPatternTest() { int flags = Pattern.LITERAL; Pattern pattern = Pattern.compile("abc\\t$^", flags); @@ -874,6 +698,7 @@ flags |= Pattern.CANON_EQ; + //Note: Possible issue Pattern p = Pattern.compile("testa\u030a", flags); check(pattern, "testa\u030a", false); check(pattern, "test\u00e5", false); @@ -922,97 +747,74 @@ flags |= Pattern.CANON_EQ; String t = toSupplementaries("test"); + //Note: Possible issue p = Pattern.compile(t + "a\u030a", flags); check(pattern, t + "a\u030a", false); check(pattern, t + "\u00e5", false); - - report("Literal pattern"); } // This test is for 4803179 // This test is also for 4808962, replacement parts - private static void literalReplacementTest() throws Exception { + @Test + public static void literalReplacementTest() { int flags = Pattern.LITERAL; Pattern pattern = Pattern.compile("abc", flags); Matcher matcher = pattern.matcher("zzzabczzz"); String replaceTest = "$0"; String result = matcher.replaceAll(replaceTest); - if (!result.equals("zzzabczzz")) - failCount++; + assertEquals(result, "zzzabczzz"); matcher.reset(); - String literalReplacement = matcher.quoteReplacement(replaceTest); + String literalReplacement = Matcher.quoteReplacement(replaceTest); result = matcher.replaceAll(literalReplacement); - if (!result.equals("zzz$0zzz")) - failCount++; + assertEquals(result, "zzz$0zzz"); matcher.reset(); replaceTest = "\\t$\\$"; - literalReplacement = matcher.quoteReplacement(replaceTest); + literalReplacement = Matcher.quoteReplacement(replaceTest); result = matcher.replaceAll(literalReplacement); - if (!result.equals("zzz\\t$\\$zzz")) - failCount++; + assertEquals(result, "zzz\\t$\\$zzz"); // Supplementary character test pattern = Pattern.compile(toSupplementaries("abc"), flags); matcher = pattern.matcher(toSupplementaries("zzzabczzz")); replaceTest = "$0"; result = matcher.replaceAll(replaceTest); - if (!result.equals(toSupplementaries("zzzabczzz"))) - failCount++; + assertEquals(result, toSupplementaries("zzzabczzz")); matcher.reset(); - literalReplacement = matcher.quoteReplacement(replaceTest); + literalReplacement = Matcher.quoteReplacement(replaceTest); result = matcher.replaceAll(literalReplacement); - if (!result.equals(toSupplementaries("zzz$0zzz"))) - failCount++; + assertEquals(result, toSupplementaries("zzz$0zzz")); matcher.reset(); replaceTest = "\\t$\\$"; - literalReplacement = matcher.quoteReplacement(replaceTest); + literalReplacement = Matcher.quoteReplacement(replaceTest); result = matcher.replaceAll(literalReplacement); - if (!result.equals(toSupplementaries("zzz\\t$\\$zzz"))) - failCount++; + assertEquals(result, toSupplementaries("zzz\\t$\\$zzz")); // IAE should be thrown if backslash or '$' is the last character // in replacement string - try { - "\uac00".replaceAll("\uac00", "$"); - failCount++; - } catch (IllegalArgumentException iie) { - } catch (Exception e) { - failCount++; - } - try { - "\uac00".replaceAll("\uac00", "\\"); - failCount++; - } catch (IllegalArgumentException iie) { - } catch (Exception e) { - failCount++; - } - report("Literal replacement"); + assertThrows(IllegalArgumentException.class, () -> "\uac00".replaceAll("\uac00", "$")); + assertThrows(IllegalArgumentException.class, () -> "\uac00".replaceAll("\uac00", "\\")); } // This test is for 4757029 - private static void regionTest() throws Exception { + @Test + public static void regionTest() { Pattern pattern = Pattern.compile("abc"); Matcher matcher = pattern.matcher("abcdefabc"); matcher.region(0,9); - if (!matcher.find()) - failCount++; - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); + assertTrue(matcher.find()); matcher.region(0,3); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); matcher.region(3,6); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.region(0,2); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); expectRegionFail(matcher, 1, -1); expectRegionFail(matcher, -1, -1); @@ -1024,43 +826,33 @@ pattern = Pattern.compile("^abc$"); matcher = pattern.matcher("zzzabczzz"); matcher.region(0,9); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.region(3,6); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); matcher.region(3,6); matcher.useAnchoringBounds(false); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); // Supplementary character test pattern = Pattern.compile(toSupplementaries("abc")); matcher = pattern.matcher(toSupplementaries("abcdefabc")); matcher.region(0,9*2); - if (!matcher.find()) - failCount++; - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); + assertTrue(matcher.find()); matcher.region(0,3*2); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); matcher.region(1,3*2); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.region(3*2,6*2); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.region(0,2*2); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.region(0,2*2+1); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); - expectRegionFail(matcher, 1*2, -1); + expectRegionFail(matcher, 2, -1); expectRegionFail(matcher, -1, -1); - expectRegionFail(matcher, -1, 1*2); + expectRegionFail(matcher, -1, 2); expectRegionFail(matcher, 5*2, 3*2); expectRegionFail(matcher, 5*2, 12*2); expectRegionFail(matcher, 12*2, 12*2); @@ -1068,55 +860,45 @@ pattern = Pattern.compile(toSupplementaries("^abc$")); matcher = pattern.matcher(toSupplementaries("zzzabczzz")); matcher.region(0,9*2); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.region(3*2,6*2); - if (!matcher.find()) - failCount++; + assertTrue(matcher.find()); matcher.region(3*2+1,6*2); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.region(3*2,6*2-1); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); matcher.region(3*2,6*2); matcher.useAnchoringBounds(false); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); // JDK-8230829 pattern = Pattern.compile("\\ud800\\udc61"); matcher = pattern.matcher("\ud800\udc61"); matcher.region(0, 1); - if (matcher.find()) { - failCount++; - System.out.println("Matched a surrogate pair" + - " that crosses border of region"); - } - if (!matcher.hitEnd()) { - failCount++; - System.out.println("Expected to hit the end when" + - " matching a surrogate pair crossing region"); - } + assertFalse(matcher.find(), "Matched a surrogate pair" + + " that crosses border of region"); - report("Regions"); + assertTrue(matcher.hitEnd(), "Expected to hit the end when" + + " matching a surrogate pair crossing region"); } private static void expectRegionFail(Matcher matcher, int index1, int index2) { + try { matcher.region(index1, index2); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Correct result - } catch (IllegalStateException ise) { + fail(); + } catch (IndexOutOfBoundsException | IllegalStateException ioobe) { // Correct result + } catch (Exception e) { + fail(); } } // This test is for 4803197 - private static void escapedSegmentTest() throws Exception { + @Test + public static void escapedSegmentTest() { Pattern pattern = Pattern.compile("\\Qdir1\\dir2\\E"); check(pattern, "dir1\\dir2", true); @@ -1136,12 +918,11 @@ pattern = Pattern.compile(toSupplementaries("(\\Qdir1\\dir2")+"\\\\E)"); check(pattern, toSupplementaries("dir1\\dir2\\"), true); - - report("Escaped segment"); } // This test is for 4792284 - private static void nonCaptureRepetitionTest() throws Exception { + @Test + public static void nonCaptureRepetitionTest() { String input = "abcdefgh;"; String[] patterns = new String[] { @@ -1157,38 +938,34 @@ "(\\w{4})+;", // capturing group - OK }; - for (int i = 0; i < patterns.length; i++) { + for (String pattern : patterns) { // Check find() - check(patterns[i], 0, input, input, true); + check(pattern, 0, input, input, true); // Check matches() - Pattern p = Pattern.compile(patterns[i]); + Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(input); - if (m.matches()) { - if (!m.group(0).equals(input)) - failCount++; - } else { - failCount++; - } + assertTrue(m.matches()); + assertEquals(m.group(0), input); } - - report("Non capturing repetition"); } // This test is for 6358731 - private static void notCapturedGroupCurlyMatchTest() throws Exception { + @Test + public static void notCapturedGroupCurlyMatchTest() { Pattern pattern = Pattern.compile("(abc)+|(abcd)+"); Matcher matcher = pattern.matcher("abcd"); - if (!matcher.matches() || + + boolean condition = !matcher.matches() || matcher.group(1) != null || - !matcher.group(2).equals("abcd")) { - failCount++; - } - report("Not captured GroupCurly"); + !matcher.group(2).equals("abcd"); + + assertFalse(condition); } // This test is for 4706545 - private static void javaCharClassTest() throws Exception { + @Test + public static void javaCharClassTest() { for (int i=0; i<1000; i++) { char c = (char)generator.nextInt(); check("{javaLowerCase}", c, Character.isLowerCase(c)); @@ -1244,8 +1021,6 @@ check("{javaISOControl}", c, Character.isISOControl(c)); check("{javaMirrored}", c, Character.isMirrored(c)); } - - report("Java character classes"); } // This test is for 4523620 @@ -1269,7 +1044,8 @@ */ // This test is for 4776374 - private static void caretBetweenTerminatorsTest() throws Exception { + @Test + public static void caretBetweenTerminatorsTest() { int flags1 = Pattern.DOTALL; int flags2 = Pattern.DOTALL | Pattern.UNIX_LINES; int flags3 = Pattern.DOTALL | Pattern.UNIX_LINES | Pattern.MULTILINE; @@ -1322,12 +1098,11 @@ check(".....^", flags4, t+"\u0085"+t, t+"\u0085", true); check(".....^", flags4, t+"\n", t+"\n", false); check(".....^", flags4, t+"\r\n", t+"\r", false); - - report("Caret between terminators"); } // This test is for 4727935 - private static void dollarAtEndTest() throws Exception { + @Test + public static void dollarAtEndTest() { int flags1 = Pattern.DOTALL; int flags2 = Pattern.DOTALL | Pattern.UNIX_LINES; int flags3 = Pattern.DOTALL | Pattern.MULTILINE; @@ -1366,34 +1141,28 @@ check(".....$."+b, flags3, t+"\n\n"+b, t+"\n\n"+b, true); check("....$"+b, flags3, t+"\n"+b, "!!!!", false); check(".....$"+b, flags3, t+"\n"+b, "!!!!", false); - - report("Dollar at End"); } // This test is for 4711773 - private static void multilineDollarTest() throws Exception { + @Test + public static void multilineDollarTest() { Pattern findCR = Pattern.compile("$", Pattern.MULTILINE); Matcher matcher = findCR.matcher("first bit\nsecond bit"); matcher.find(); - if (matcher.start(0) != 9) - failCount++; + assertEquals(matcher.start(), 9); matcher.find(); - if (matcher.start(0) != 20) - failCount++; + assertEquals(matcher.start(0), 20); // Supplementary character test matcher = findCR.matcher(toSupplementaries("first bit\n second bit")); // double BMP chars matcher.find(); - if (matcher.start(0) != 9*2) - failCount++; + assertEquals(matcher.start(0), 9*2); matcher.find(); - if (matcher.start(0) != 20*2) - failCount++; - - report("Multiline Dollar"); + assertEquals(matcher.start(0), 20*2); } - private static void reluctantRepetitionTest() throws Exception { + @Test + public static void reluctantRepetitionTest() { Pattern p = Pattern.compile("1(\\s\\S+?){1,3}?[\\s,]2"); check(p, "1 word word word 2", true); check(p, "1 wor wo w 2", true); @@ -1411,11 +1180,9 @@ p = Pattern.compile(toSupplementaries("([a-z])+?c")); m = p.matcher(toSupplementaries("ababcdefdec")); check(m, toSupplementaries("ababc")); - - report("Reluctant Repetition"); } - private static Pattern serializedPattern(Pattern p) throws Exception { + public static Pattern serializedPattern(Pattern p) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(p); @@ -1426,54 +1193,45 @@ } } - private static void serializeTest() throws Exception { + @Test + public static void serializeTest() throws Exception { String patternStr = "(b)"; String matchStr = "b"; Pattern pattern = Pattern.compile(patternStr); Pattern serializedPattern = serializedPattern(pattern); Matcher matcher = serializedPattern.matcher(matchStr); - if (!matcher.matches()) - failCount++; - if (matcher.groupCount() != 1) - failCount++; + assertTrue(matcher.matches()); + assertEquals(matcher.groupCount(), 1); pattern = Pattern.compile("a(?-i)b", Pattern.CASE_INSENSITIVE); serializedPattern = serializedPattern(pattern); - if (!serializedPattern.matcher("Ab").matches()) - failCount++; - if (serializedPattern.matcher("AB").matches()) - failCount++; - - report("Serialization"); + assertTrue(serializedPattern.matcher("Ab").matches()); + assertFalse(serializedPattern.matcher("AB").matches()); } - private static void gTest() { + @Test + public static void gTest() { Pattern pattern = Pattern.compile("\\G\\w"); Matcher matcher = pattern.matcher("abc#x#x"); matcher.find(); matcher.find(); matcher.find(); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); pattern = Pattern.compile("\\GA*"); matcher = pattern.matcher("1A2AA3"); matcher.find(); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); pattern = Pattern.compile("\\GA*"); matcher = pattern.matcher("1A2AA3"); - if (!matcher.find(1)) - failCount++; + assertTrue(matcher.find(1)); matcher.find(); - if (matcher.find()) - failCount++; - - report("\\G"); + assertFalse(matcher.find()); } - private static void zTest() { + @Test + public static void zTest() { Pattern pattern = Pattern.compile("foo\\Z"); // Positives check(pattern, "foo\u0085", true); @@ -1495,87 +1253,74 @@ check(pattern, "foo\u0085", false); check(pattern, "foo\u2028", false); check(pattern, "foo\u2029", false); - - report("\\Z"); } - private static void replaceFirstTest() { + @Test + public static void replaceFirstTest() { Pattern pattern = Pattern.compile("(ab)(c*)"); Matcher matcher = pattern.matcher("abccczzzabcczzzabccc"); - if (!matcher.replaceFirst("test").equals("testzzzabcczzzabccc")) - failCount++; + assertEquals(matcher.replaceFirst("test"), "testzzzabcczzzabccc"); matcher.reset("zzzabccczzzabcczzzabccczzz"); - if (!matcher.replaceFirst("test").equals("zzztestzzzabcczzzabccczzz")) - failCount++; + assertEquals(matcher.replaceFirst("test"), "zzztestzzzabcczzzabccczzz"); matcher.reset("zzzabccczzzabcczzzabccczzz"); String result = matcher.replaceFirst("$1"); - if (!result.equals("zzzabzzzabcczzzabccczzz")) - failCount++; + assertEquals(result,"zzzabzzzabcczzzabccczzz"); matcher.reset("zzzabccczzzabcczzzabccczzz"); result = matcher.replaceFirst("$2"); - if (!result.equals("zzzccczzzabcczzzabccczzz")) - failCount++; + assertEquals(result, "zzzccczzzabcczzzabccczzz"); pattern = Pattern.compile("a*"); matcher = pattern.matcher("aaaaaaaaaa"); - if (!matcher.replaceFirst("test").equals("test")) - failCount++; + assertEquals(matcher.replaceFirst("test"), "test"); pattern = Pattern.compile("a+"); matcher = pattern.matcher("zzzaaaaaaaaaa"); - if (!matcher.replaceFirst("test").equals("zzztest")) - failCount++; + assertEquals(matcher.replaceFirst("test"), "zzztest"); // Supplementary character test pattern = Pattern.compile(toSupplementaries("(ab)(c*)")); matcher = pattern.matcher(toSupplementaries("abccczzzabcczzzabccc")); - if (!matcher.replaceFirst(toSupplementaries("test")) - .equals(toSupplementaries("testzzzabcczzzabccc"))) - failCount++; + result = matcher.replaceFirst(toSupplementaries("test")); + assertEquals(result, toSupplementaries("testzzzabcczzzabccc")); matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); - if (!matcher.replaceFirst(toSupplementaries("test")). - equals(toSupplementaries("zzztestzzzabcczzzabccczzz"))) - failCount++; + result = matcher.replaceFirst(toSupplementaries("test")); + assertEquals(result, toSupplementaries("zzztestzzzabcczzzabccczzz")); matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); result = matcher.replaceFirst("$1"); - if (!result.equals(toSupplementaries("zzzabzzzabcczzzabccczzz"))) - failCount++; + assertEquals(result, toSupplementaries("zzzabzzzabcczzzabccczzz")); matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); result = matcher.replaceFirst("$2"); - if (!result.equals(toSupplementaries("zzzccczzzabcczzzabccczzz"))) - failCount++; + assertEquals(result, toSupplementaries("zzzccczzzabcczzzabccczzz")); pattern = Pattern.compile(toSupplementaries("a*")); matcher = pattern.matcher(toSupplementaries("aaaaaaaaaa")); - if (!matcher.replaceFirst(toSupplementaries("test")).equals(toSupplementaries("test"))) - failCount++; + + result = matcher.replaceFirst(toSupplementaries("test")); + assertEquals(result,toSupplementaries("test")); pattern = Pattern.compile(toSupplementaries("a+")); matcher = pattern.matcher(toSupplementaries("zzzaaaaaaaaaa")); - if (!matcher.replaceFirst(toSupplementaries("test")).equals(toSupplementaries("zzztest"))) - failCount++; - - report("Replace First"); + result = matcher.replaceFirst(toSupplementaries("test")); + assertEquals(result, toSupplementaries("zzztest")); } - private static void unixLinesTest() { + @Test + public static void unixLinesTest() { Pattern pattern = Pattern.compile(".*"); Matcher matcher = pattern.matcher("aa\u2028blah"); matcher.find(); - if (!matcher.group(0).equals("aa")) - failCount++; + assertEquals(matcher.group(0), "aa"); pattern = Pattern.compile(".*", Pattern.UNIX_LINES); matcher = pattern.matcher("aa\u2028blah"); matcher.find(); - if (!matcher.group(0).equals("aa\u2028blah")) - failCount++; + assertEquals(matcher.group(0), "aa\u2028blah"); pattern = Pattern.compile("[az]$", Pattern.MULTILINE | Pattern.UNIX_LINES); @@ -1586,129 +1331,106 @@ pattern = Pattern.compile(".*"); matcher = pattern.matcher(toSupplementaries("aa\u2028blah")); matcher.find(); - if (!matcher.group(0).equals(toSupplementaries("aa"))) - failCount++; + assertEquals(matcher.group(0), toSupplementaries("aa")); pattern = Pattern.compile(".*", Pattern.UNIX_LINES); matcher = pattern.matcher(toSupplementaries("aa\u2028blah")); matcher.find(); - if (!matcher.group(0).equals(toSupplementaries("aa\u2028blah"))) - failCount++; + assertEquals(matcher.group(0), toSupplementaries("aa\u2028blah")); pattern = Pattern.compile(toSupplementaries("[az]$"), Pattern.MULTILINE | Pattern.UNIX_LINES); matcher = pattern.matcher(toSupplementaries("aa\u2028zz")); check(matcher, toSupplementaries("a\u2028"), false); - - report("Unix Lines"); } - private static void commentsTest() { + @Test + public static void commentsTest() { int flags = Pattern.COMMENTS; Pattern pattern = Pattern.compile("aa \\# aa", flags); Matcher matcher = pattern.matcher("aa#aa"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("aa # blah", flags); matcher = pattern.matcher("aa"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("aa blah", flags); matcher = pattern.matcher("aablah"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("aa # blah blech ", flags); matcher = pattern.matcher("aa"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("aa # blah\n ", flags); matcher = pattern.matcher("aa"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("aa # blah\nbc # blech", flags); matcher = pattern.matcher("aabc"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("aa # blah\nbc# blech", flags); matcher = pattern.matcher("aabc"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("aa # blah\nbc\\# blech", flags); matcher = pattern.matcher("aabc#blech"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); // Supplementary character test pattern = Pattern.compile(toSupplementaries("aa \\# aa"), flags); matcher = pattern.matcher(toSupplementaries("aa#aa")); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile(toSupplementaries("aa # blah"), flags); matcher = pattern.matcher(toSupplementaries("aa")); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile(toSupplementaries("aa blah"), flags); matcher = pattern.matcher(toSupplementaries("aablah")); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile(toSupplementaries("aa # blah blech "), flags); matcher = pattern.matcher(toSupplementaries("aa")); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile(toSupplementaries("aa # blah\n "), flags); matcher = pattern.matcher(toSupplementaries("aa")); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile(toSupplementaries("aa # blah\nbc # blech"), flags); matcher = pattern.matcher(toSupplementaries("aabc")); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile(toSupplementaries("aa # blah\nbc# blech"), flags); matcher = pattern.matcher(toSupplementaries("aabc")); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile(toSupplementaries("aa # blah\nbc\\# blech"), flags); matcher = pattern.matcher(toSupplementaries("aabc#blech")); - if (!matcher.matches()) - failCount++; - - report("Comments"); + assertTrue(matcher.matches()); } - private static void caseFoldingTest() { // bug 4504687 + @Test + public static void caseFoldingTest() { // bug 4504687 int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; Pattern pattern = Pattern.compile("aa", flags); Matcher matcher = pattern.matcher("ab"); - if (matcher.matches()) - failCount++; + assertFalse(matcher.matches()); pattern = Pattern.compile("aA", flags); matcher = pattern.matcher("ab"); - if (matcher.matches()) - failCount++; + assertFalse(matcher.matches()); pattern = Pattern.compile("aa", flags); matcher = pattern.matcher("aB"); - if (matcher.matches()) - failCount++; + assertFalse(matcher.matches()); + matcher = pattern.matcher("Ab"); - if (matcher.matches()) - failCount++; + assertFalse(matcher.matches()); // ASCII "a" // Latin-1 Supplement "a" + grave @@ -1746,46 +1468,35 @@ for (int i = 0; i < patterns.length; i++) { pattern = Pattern.compile(patterns[i], flags); matcher = pattern.matcher(texts[i]); - if (matcher.matches() != expected[i]) { - System.out.println("<1> Failed at " + i); - failCount++; - } + assertEquals(matcher.matches(), expected[i], "<1> Failed at " + i); } flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; for (int i = 0; i < patterns.length; i++) { pattern = Pattern.compile(patterns[i], flags); matcher = pattern.matcher(texts[i]); - if (!matcher.matches()) { - System.out.println("<2> Failed at " + i); - failCount++; - } + assertTrue(matcher.matches(), "<2> Failed at " + i); } // flag unicode_case alone should do nothing flags = Pattern.UNICODE_CASE; for (int i = 0; i < patterns.length; i++) { pattern = Pattern.compile(patterns[i], flags); matcher = pattern.matcher(texts[i]); - if (matcher.matches()) { - System.out.println("<3> Failed at " + i); - failCount++; - } + assertFalse(matcher.matches(), "<3> Failed at " + i); } // Special cases: i, I, u+0131 and u+0130 flags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE; pattern = Pattern.compile("[h-j]+", flags); - if (!pattern.matcher("\u0131\u0130").matches()) - failCount++; - report("Case Folding"); + assertTrue(pattern.matcher("\u0131\u0130").matches()); } - private static void appendTest() { + @Test + public static void appendTest() { Pattern pattern = Pattern.compile("(ab)(cd)"); Matcher matcher = pattern.matcher("abcd"); String result = matcher.replaceAll("$2$1"); - if (!result.equals("cdab")) - failCount++; + assertEquals(result, "cdab"); String s1 = "Swap all: first = 123, second = 456"; String s2 = "Swap one: first = 123, second = 456"; @@ -1794,8 +1505,7 @@ matcher = pattern.matcher(s1); result = matcher.replaceAll(r); - if (!result.equals("Swap all: 123 = first, 456 = second")) - failCount++; + assertEquals(result, "Swap all: 123 = first, 456 = second"); matcher = pattern.matcher(s2); @@ -1804,16 +1514,14 @@ matcher.appendReplacement(sb, r); matcher.appendTail(sb); result = sb.toString(); - if (!result.equals("Swap one: 123 = first, second = 456")) - failCount++; + assertEquals(result, "Swap one: 123 = first, second = 456"); } // Supplementary character test pattern = Pattern.compile(toSupplementaries("(ab)(cd)")); matcher = pattern.matcher(toSupplementaries("abcd")); result = matcher.replaceAll("$2$1"); - if (!result.equals(toSupplementaries("cdab"))) - failCount++; + assertEquals(result, toSupplementaries("cdab")); s1 = toSupplementaries("Swap all: first = 123, second = 456"); s2 = toSupplementaries("Swap one: first = 123, second = 456"); @@ -1822,8 +1530,7 @@ matcher = pattern.matcher(s1); result = matcher.replaceAll(r); - if (!result.equals(toSupplementaries("Swap all: 123 = first, 456 = second"))) - failCount++; + assertEquals(result, toSupplementaries("Swap all: 123 = first, 456 = second")); matcher = pattern.matcher(s2); @@ -1832,49 +1539,38 @@ matcher.appendReplacement(sb, r); matcher.appendTail(sb); result = sb.toString(); - if (!result.equals(toSupplementaries("Swap one: 123 = first, second = 456"))) - failCount++; + assertEquals(result, toSupplementaries("Swap one: 123 = first, second = 456")); } - report("Append"); } - private static void splitTest() { + @Test + public static void splitTest() { Pattern pattern = Pattern.compile(":"); String[] result = pattern.split("foo:and:boo", 2); - if (!result[0].equals("foo")) - failCount++; - if (!result[1].equals("and:boo")) - failCount++; + assertEquals(result[0], "foo"); + assertEquals(result[1], "and:boo"); // Supplementary character test Pattern patternX = Pattern.compile(toSupplementaries("X")); result = patternX.split(toSupplementaries("fooXandXboo"), 2); - if (!result[0].equals(toSupplementaries("foo"))) - failCount++; - if (!result[1].equals(toSupplementaries("andXboo"))) - failCount++; + assertEquals(result[0], toSupplementaries("foo")); + assertEquals(result[1], toSupplementaries("andXboo")); CharBuffer cb = CharBuffer.allocate(100); cb.put("foo:and:boo"); cb.flip(); result = pattern.split(cb); - if (!result[0].equals("foo")) - failCount++; - if (!result[1].equals("and")) - failCount++; - if (!result[2].equals("boo")) - failCount++; + assertEquals(result[0], "foo"); + assertEquals(result[1], "and"); + assertEquals(result[2], "boo"); // Supplementary character test CharBuffer cbs = CharBuffer.allocate(100); cbs.put(toSupplementaries("fooXandXboo")); cbs.flip(); result = patternX.split(cbs); - if (!result[0].equals(toSupplementaries("foo"))) - failCount++; - if (!result[1].equals(toSupplementaries("and"))) - failCount++; - if (!result[2].equals(toSupplementaries("boo"))) - failCount++; + assertEquals(result[0], toSupplementaries("foo")); + assertEquals(result[1], toSupplementaries("and")); + assertEquals(result[2], toSupplementaries("boo")); String source = "0123456789"; for (int limit=-2; limit<3; limit++) { @@ -1884,27 +1580,17 @@ if ((limit == 0) && (x == 9)) { // expected dropping of "" - if (result.length != 1) - failCount++; - if (!result[0].equals("012345678")) { - failCount++; - } + assertEquals(result.length, 1); + assertEquals(result[0], "012345678"); } else { - if (result.length != expectedLength) { - failCount++; - } + assertEquals(result.length, expectedLength); + if (!result[0].equals(source.substring(0,x))) { - if (limit != 1) { - failCount++; - } else { - if (!result[0].equals(source.substring(0,10))) { - failCount++; - } - } + assertEquals(limit, 1); + assertEquals(result[0], source.substring(0,10)); } if (expectedLength > 1) { // Check segment 2 - if (!result[1].equals(source.substring(x+1,10))) - failCount++; + assertEquals(result[1], source.substring(x+1,10)); } } } @@ -1912,19 +1598,15 @@ // Check the case for no match found for (int limit=-2; limit<3; limit++) { result = source.split("e", limit); - if (result.length != 1) - failCount++; - if (!result[0].equals(source)) - failCount++; + assertEquals(result.length, 1); + assertEquals(result[0], source); } // Check the case for limit == 0, source = ""; // split() now returns 0-length for empty source "" see #6559590 source = ""; result = source.split("e", 0); - if (result.length != 1) - failCount++; - if (!result[0].equals(source)) - failCount++; + assertEquals(result.length, 1); + assertEquals(result[0], source); // Check both split() and splitAsStraem(), especially for zero-lenth // input and zero-lenth match cases @@ -1976,48 +1658,39 @@ }; for (int i = 0; i < input.length; i++) { pattern = Pattern.compile(input[i][0]); - if (!Arrays.equals(pattern.split(input[i][1]), expected[i])) { - failCount++; - } - if (input[i][1].length() > 0 && // splitAsStream() return empty resulting + assertTrue(Arrays.equals(pattern.split(input[i][1]), expected[i])); + + assertFalse(input[i][1].length() > 0 && // splitAsStream() return empty resulting // array for zero-length input for now !Arrays.equals(pattern.splitAsStream(input[i][1]).toArray(), - expected[i])) { - failCount++; - } + expected[i])); } - report("Split"); } - private static void negationTest() { + @Test + public static void negationTest() { Pattern pattern = Pattern.compile("[\\[@^]+"); Matcher matcher = pattern.matcher("@@@@[[[[^^^^"); - if (!matcher.find()) - failCount++; - if (!matcher.group(0).equals("@@@@[[[[^^^^")) - failCount++; + assertTrue(matcher.find()); + assertEquals(matcher.group(0), "@@@@[[[[^^^^"); + pattern = Pattern.compile("[@\\[^]+"); matcher = pattern.matcher("@@@@[[[[^^^^"); - if (!matcher.find()) - failCount++; - if (!matcher.group(0).equals("@@@@[[[[^^^^")) - failCount++; + assertTrue(matcher.find()); + assertEquals(matcher.group(0), "@@@@[[[[^^^^"); + pattern = Pattern.compile("[@\\[^@]+"); matcher = pattern.matcher("@@@@[[[[^^^^"); - if (!matcher.find()) - failCount++; - if (!matcher.group(0).equals("@@@@[[[[^^^^")) - failCount++; + assertTrue(matcher.find()); + assertEquals(matcher.group(0), "@@@@[[[[^^^^"); pattern = Pattern.compile("\\)"); matcher = pattern.matcher("xxx)xxx"); - if (!matcher.find()) - failCount++; - - report("Negation"); + assertTrue(matcher.find()); } - private static void ampersandTest() { + @Test + public static void ampersandTest() { Pattern pattern = Pattern.compile("[&@]+"); check(pattern, "@@@@&&&&", true); @@ -2026,112 +1699,87 @@ pattern = Pattern.compile("[@\\&]+"); check(pattern, "@@@@&&&&", true); - - report("Ampersand"); } - private static void octalTest() throws Exception { + @Test + public static void octalTest() { Pattern pattern = Pattern.compile("\\u0007"); Matcher matcher = pattern.matcher("\u0007"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("\\07"); matcher = pattern.matcher("\u0007"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("\\007"); matcher = pattern.matcher("\u0007"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("\\0007"); matcher = pattern.matcher("\u0007"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("\\040"); matcher = pattern.matcher("\u0020"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("\\0403"); matcher = pattern.matcher("\u00203"); - if (!matcher.matches()) - failCount++; + assertTrue(matcher.matches()); pattern = Pattern.compile("\\0103"); matcher = pattern.matcher("\u0043"); - if (!matcher.matches()) - failCount++; - - report("Octal"); + assertTrue(matcher.matches()); } - private static void longPatternTest() throws Exception { + @Test + public static void longPatternTest() { try { - Pattern pattern = Pattern.compile( + Pattern.compile( "a 32-character-long pattern xxxx"); - pattern = Pattern.compile("a 33-character-long pattern xxxxx"); - pattern = Pattern.compile("a thirty four character long regex"); - StringBuffer patternToBe = new StringBuffer(101); + Pattern.compile("a 33-character-long pattern xxxxx"); + Pattern.compile("a thirty four character long regex"); + StringBuilder patternToBe = new StringBuilder(101); for (int i=0; i<100; i++) patternToBe.append((char)(97 + i%26)); - pattern = Pattern.compile(patternToBe.toString()); + Pattern.compile(patternToBe.toString()); } catch (PatternSyntaxException e) { - failCount++; + fail(); } // Supplementary character test try { - Pattern pattern = Pattern.compile( + Pattern.compile( toSupplementaries("a 32-character-long pattern xxxx")); - pattern = Pattern.compile(toSupplementaries("a 33-character-long pattern xxxxx")); - pattern = Pattern.compile(toSupplementaries("a thirty four character long regex")); - StringBuffer patternToBe = new StringBuffer(101*2); + Pattern.compile(toSupplementaries("a 33-character-long pattern xxxxx")); + Pattern.compile(toSupplementaries("a thirty four character long regex")); + StringBuilder patternToBe = new StringBuilder(101*2); for (int i=0; i<100; i++) patternToBe.append(Character.toChars(Character.MIN_SUPPLEMENTARY_CODE_POINT + 97 + i%26)); - pattern = Pattern.compile(patternToBe.toString()); + Pattern.compile(patternToBe.toString()); } catch (PatternSyntaxException e) { - failCount++; + fail(); } - report("LongPattern"); } - private static void group0Test() throws Exception { + @Test + public static void group0Test() { Pattern pattern = Pattern.compile("(tes)ting"); Matcher matcher = pattern.matcher("testing"); check(matcher, "testing"); matcher.reset("testing"); - if (matcher.lookingAt()) { - if (!matcher.group(0).equals("testing")) - failCount++; - } else { - failCount++; - } + assertTrue(matcher.lookingAt()); + assertEquals(matcher.group(0), "testing"); matcher.reset("testing"); - if (matcher.matches()) { - if (!matcher.group(0).equals("testing")) - failCount++; - } else { - failCount++; - } + assertTrue(matcher.matches()); + assertEquals(matcher.group(0), "testing"); pattern = Pattern.compile("(tes)ting"); matcher = pattern.matcher("testing"); - if (matcher.lookingAt()) { - if (!matcher.group(0).equals("testing")) - failCount++; - } else { - failCount++; - } + assertTrue(matcher.lookingAt()); + assertEquals(matcher.group(0), "testing"); pattern = Pattern.compile("^(tes)ting"); matcher = pattern.matcher("testing"); - if (matcher.matches()) { - if (!matcher.group(0).equals("testing")) - failCount++; - } else { - failCount++; - } + assertTrue(matcher.matches()); + assertEquals(matcher.group(0), "testing"); // Supplementary character test pattern = Pattern.compile(toSupplementaries("(tes)ting")); @@ -2139,112 +1787,77 @@ check(matcher, toSupplementaries("testing")); matcher.reset(toSupplementaries("testing")); - if (matcher.lookingAt()) { - if (!matcher.group(0).equals(toSupplementaries("testing"))) - failCount++; - } else { - failCount++; - } + assertTrue(matcher.lookingAt()); + assertEquals(matcher.group(0), toSupplementaries("testing")); matcher.reset(toSupplementaries("testing")); - if (matcher.matches()) { - if (!matcher.group(0).equals(toSupplementaries("testing"))) - failCount++; - } else { - failCount++; - } + assertTrue(matcher.matches()); + assertEquals(matcher.group(0), toSupplementaries("testing")); pattern = Pattern.compile(toSupplementaries("(tes)ting")); matcher = pattern.matcher(toSupplementaries("testing")); - if (matcher.lookingAt()) { - if (!matcher.group(0).equals(toSupplementaries("testing"))) - failCount++; - } else { - failCount++; - } + assertTrue(matcher.lookingAt()); + assertEquals(matcher.group(0), toSupplementaries("testing")); pattern = Pattern.compile(toSupplementaries("^(tes)ting")); matcher = pattern.matcher(toSupplementaries("testing")); - if (matcher.matches()) { - if (!matcher.group(0).equals(toSupplementaries("testing"))) - failCount++; - } else { - failCount++; - } - report("Group0"); + assertTrue(matcher.matches()); + assertEquals(matcher.group(0), toSupplementaries("testing")); } - private static void findIntTest() throws Exception { + @Test + public static void findIntTest() { Pattern p = Pattern.compile("blah"); Matcher m = p.matcher("zzzzblahzzzzzblah"); boolean result = m.find(2); - if (!result) - failCount++; - p = Pattern.compile("$"); - m = p.matcher("1234567890"); - result = m.find(10); - if (!result) - failCount++; - try { - result = m.find(11); - failCount++; - } catch (IndexOutOfBoundsException e) { - // correct result - } + assertTrue(result); + + final Pattern p2 = Pattern.compile("$"); + final Matcher m2 = p2.matcher("1234567890"); + result = m2.find(10); + assertTrue(result); + assertThrows(IndexOutOfBoundsException.class, () -> m2.find(11)); // Supplementary character test p = Pattern.compile(toSupplementaries("blah")); m = p.matcher(toSupplementaries("zzzzblahzzzzzblah")); result = m.find(2); - if (!result) - failCount++; - - report("FindInt"); + assertTrue(result); } - private static void emptyPatternTest() throws Exception { + @Test + public static void emptyPatternTest() { Pattern p = Pattern.compile(""); - Matcher m = p.matcher("foo"); + final Matcher m = p.matcher("foo"); // Should find empty pattern at beginning of input boolean result = m.find(); - if (result != true) - failCount++; - if (m.start() != 0) - failCount++; + assertTrue(result); + assertEquals(m.start(), 0); // Should not match entire input if input is not empty m.reset(); result = m.matches(); - if (result == true) - failCount++; + assertFalse(result); - try { - m.start(0); - failCount++; - } catch (IllegalStateException e) { - // Correct result - } + assertThrows(IllegalStateException.class, () -> m.start(0)); // Should match entire input if input is empty m.reset(""); result = m.matches(); - if (result != true) - failCount++; + assertTrue(result); result = Pattern.matches("", ""); - if (result != true) - failCount++; + assertTrue(result); result = Pattern.matches("", "foo"); - if (result == true) - failCount++; - report("EmptyPattern"); + assertFalse(result); } - private static void charClassTest() throws Exception { + @Test + public static void charClassTest() { Pattern pattern = Pattern.compile("blah[ab]]blech"); check(pattern, "blahb]blech", true); @@ -2258,21 +1871,19 @@ pattern = Pattern.compile(toSupplementaries("[abc[def]]")); check(pattern, toSupplementaries("b"), true); - try { - // u00ff when UNICODE_CASE - pattern = Pattern.compile("[ab\u00ffcd]", - Pattern.CASE_INSENSITIVE| - Pattern.UNICODE_CASE); - check(pattern, "ab\u00ffcd", true); - check(pattern, "Ab\u0178Cd", true); - - // u00b5 when UNICODE_CASE - pattern = Pattern.compile("[ab\u00b5cd]", - Pattern.CASE_INSENSITIVE| - Pattern.UNICODE_CASE); - check(pattern, "ab\u00b5cd", true); - check(pattern, "Ab\u039cCd", true); - } catch (Exception e) { failCount++; } + // u00ff when UNICODE_CASE + pattern = Pattern.compile("[ab\u00ffcd]", + Pattern.CASE_INSENSITIVE| + Pattern.UNICODE_CASE); + check(pattern, "ab\u00ffcd", true); + check(pattern, "Ab\u0178Cd", true); + + // u00b5 when UNICODE_CASE + pattern = Pattern.compile("[ab\u00b5cd]", + Pattern.CASE_INSENSITIVE| + Pattern.UNICODE_CASE); + check(pattern, "ab\u00b5cd", true); + check(pattern, "Ab\u039cCd", true); /* Special cases (1)LatinSmallLetterLongS u+017f @@ -2283,13 +1894,12 @@ */ int flags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE; pattern = Pattern.compile("[sik\u00c5]+", flags); - if (!pattern.matcher("\u017f\u0130\u0131\u212a\u212b").matches()) - failCount++; + assertTrue(pattern.matcher("\u017f\u0130\u0131\u212a\u212b").matches()); - report("CharClass"); } - private static void caretTest() throws Exception { + @Test + public static void caretTest() { Pattern pattern = Pattern.compile("\\w*"); Matcher matcher = pattern.matcher("a#bc#def##g"); check(matcher, "a"); @@ -2301,14 +1911,12 @@ check(matcher, ""); check(matcher, "g"); check(matcher, ""); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); pattern = Pattern.compile("^\\w*"); matcher = pattern.matcher("a#bc#def##g"); check(matcher, "a"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); pattern = Pattern.compile("\\w"); matcher = pattern.matcher("abc##x"); @@ -2316,97 +1924,78 @@ check(matcher, "b"); check(matcher, "c"); check(matcher, "x"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); pattern = Pattern.compile("^\\w"); matcher = pattern.matcher("abc##x"); check(matcher, "a"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); pattern = Pattern.compile("\\A\\p{Alpha}{3}"); matcher = pattern.matcher("abcdef-ghi\njklmno"); check(matcher, "abc"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); pattern = Pattern.compile("^\\p{Alpha}{3}", Pattern.MULTILINE); matcher = pattern.matcher("abcdef-ghi\njklmno"); check(matcher, "abc"); check(matcher, "jkl"); - if (matcher.find()) - failCount++; + assertFalse(matcher.find()); pattern = Pattern.compile("^", Pattern.MULTILINE); matcher = pattern.matcher("this is some text"); String result = matcher.replaceAll("X"); - if (!result.equals("Xthis is some text")) - failCount++; + assertEquals(result, "Xthis is some text"); pattern = Pattern.compile("^"); matcher = pattern.matcher("this is some text"); result = matcher.replaceAll("X"); - if (!result.equals("Xthis is some text")) - failCount++; + assertEquals(result, "Xthis is some text"); pattern = Pattern.compile("^", Pattern.MULTILINE | Pattern.UNIX_LINES); matcher = pattern.matcher("this is some text\n"); result = matcher.replaceAll("X"); - if (!result.equals("Xthis is some text\n")) - failCount++; - - report("Caret"); + assertEquals(result, "Xthis is some text\n"); } - private static void groupCaptureTest() throws Exception { + @Test + public static void groupCaptureTest() { // Independent group - Pattern pattern = Pattern.compile("x+(?>y+)z+"); - Matcher matcher = pattern.matcher("xxxyyyzzz"); - matcher.find(); - try { - String blah = matcher.group(1); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Good result - } + assertThrows(IndexOutOfBoundsException.class, () -> { + Pattern pattern = Pattern.compile("x+(?>y+)z+"); + Matcher matcher = pattern.matcher("xxxyyyzzz"); + matcher.find(); + matcher.group(1); + }); + // Pure group - pattern = Pattern.compile("x+(?:y+)z+"); - matcher = pattern.matcher("xxxyyyzzz"); - matcher.find(); - try { + assertThrows(IndexOutOfBoundsException.class, () -> { + Pattern pattern = Pattern.compile("x+(?:y+)z+"); + Matcher matcher = pattern.matcher("xxxyyyzzz"); + matcher.find(); String blah = matcher.group(1); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Good result - } + }); // Supplementary character tests // Independent group - pattern = Pattern.compile(toSupplementaries("x+(?>y+)z+")); - matcher = pattern.matcher(toSupplementaries("xxxyyyzzz")); - matcher.find(); - try { + assertThrows(IndexOutOfBoundsException.class, () -> { + Pattern pattern = Pattern.compile(toSupplementaries("x+(?>y+)z+")); + Matcher matcher = pattern.matcher(toSupplementaries("xxxyyyzzz")); + matcher.find(); String blah = matcher.group(1); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Good result - } + }); + // Pure group - pattern = Pattern.compile(toSupplementaries("x+(?:y+)z+")); - matcher = pattern.matcher(toSupplementaries("xxxyyyzzz")); - matcher.find(); - try { + assertThrows(IndexOutOfBoundsException.class, () -> { + Pattern pattern = Pattern.compile(toSupplementaries("x+(?:y+)z+")); + Matcher matcher = pattern.matcher(toSupplementaries("xxxyyyzzz")); + matcher.find(); String blah = matcher.group(1); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Good result - } - - report("GroupCapture"); + }); } - private static void backRefTest() throws Exception { + @Test + public static void backRefTest() { Pattern pattern = Pattern.compile("(a*)bc\\1"); check(pattern, "zzzaabcazzz", true); @@ -2419,15 +2008,11 @@ pattern = Pattern.compile("(abc)(def)\\3"); check(pattern, "abcdefabc", false); - try { - for (int i = 1; i < 10; i++) { - // Make sure backref 1-9 are always accepted - pattern = Pattern.compile("abcdef\\" + i); - // and fail to match if the target group does not exit - check(pattern, "abcdef", false); - } - } catch(PatternSyntaxException e) { - failCount++; + for (int i = 1; i < 10; i++) { + // Make sure backref 1-9 are always accepted + pattern = Pattern.compile("abcdef\\" + i); + // and fail to match if the target group does not exit + check(pattern, "abcdef", false); } pattern = Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\\11"); @@ -2459,8 +2044,6 @@ pattern = Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11")); check(pattern, toSupplementaries("abcdefghijkk"), true); - - report("BackRef"); } /** @@ -2468,209 +2051,170 @@ * There is no empty line to be matched in the sequence \u000D\u000A * but there is an empty line in the sequence \u000A\u000D. */ - private static void anchorTest() throws Exception { + @Test + public static void anchorTest() { Pattern p = Pattern.compile("^.*$", Pattern.MULTILINE); Matcher m = p.matcher("blah1\r\nblah2"); m.find(); m.find(); - if (!m.group().equals("blah2")) - failCount++; + assertEquals(m.group(), "blah2"); m.reset("blah1\n\rblah2"); m.find(); m.find(); m.find(); - if (!m.group().equals("blah2")) - failCount++; + assertEquals(m.group(), "blah2"); // Test behavior of $ with \r\n at end of input p = Pattern.compile(".+$"); m = p.matcher("blah1\r\n"); - if (!m.find()) - failCount++; - if (!m.group().equals("blah1")) - failCount++; - if (m.find()) - failCount++; + assertTrue(m.find()); + assertEquals(m.group(), "blah1"); + assertFalse(m.find()); // Test behavior of $ with \r\n at end of input in multiline p = Pattern.compile(".+$", Pattern.MULTILINE); m = p.matcher("blah1\r\n"); - if (!m.find()) - failCount++; - if (m.find()) - failCount++; + assertTrue(m.find()); + assertFalse(m.find()); // Test for $ recognition of \u0085 for bug 4527731 p = Pattern.compile(".+$", Pattern.MULTILINE); m = p.matcher("blah1\u0085"); - if (!m.find()) - failCount++; + assertTrue(m.find()); // Supplementary character test p = Pattern.compile("^.*$", Pattern.MULTILINE); m = p.matcher(toSupplementaries("blah1\r\nblah2")); m.find(); m.find(); - if (!m.group().equals(toSupplementaries("blah2"))) - failCount++; + assertEquals(m.group(), toSupplementaries("blah2")); m.reset(toSupplementaries("blah1\n\rblah2")); m.find(); m.find(); m.find(); - if (!m.group().equals(toSupplementaries("blah2"))) - failCount++; + + assertEquals(m.group(), toSupplementaries("blah2")); // Test behavior of $ with \r\n at end of input p = Pattern.compile(".+$"); m = p.matcher(toSupplementaries("blah1\r\n")); - if (!m.find()) - failCount++; - if (!m.group().equals(toSupplementaries("blah1"))) - failCount++; - if (m.find()) - failCount++; + assertTrue(m.find()); + assertEquals(m.group(), toSupplementaries("blah1")); + assertFalse(m.find()); // Test behavior of $ with \r\n at end of input in multiline p = Pattern.compile(".+$", Pattern.MULTILINE); m = p.matcher(toSupplementaries("blah1\r\n")); - if (!m.find()) - failCount++; - if (m.find()) - failCount++; + assertTrue(m.find()); + assertFalse(m.find()); // Test for $ recognition of \u0085 for bug 4527731 p = Pattern.compile(".+$", Pattern.MULTILINE); m = p.matcher(toSupplementaries("blah1\u0085")); - if (!m.find()) - failCount++; - - report("Anchors"); + assertTrue(m.find()); } /** * A basic sanity test of Matcher.lookingAt(). */ - private static void lookingAtTest() throws Exception { + @Test + public static void lookingAtTest() { Pattern p = Pattern.compile("(ab)(c*)"); Matcher m = p.matcher("abccczzzabcczzzabccc"); - if (!m.lookingAt()) - failCount++; + assertTrue(m.lookingAt()); - if (!m.group().equals(m.group(0))) - failCount++; + assertEquals(m.group(), m.group(0)); m = p.matcher("zzzabccczzzabcczzzabccczzz"); - if (m.lookingAt()) - failCount++; + assertFalse(m.lookingAt()); // Supplementary character test p = Pattern.compile(toSupplementaries("(ab)(c*)")); m = p.matcher(toSupplementaries("abccczzzabcczzzabccc")); - if (!m.lookingAt()) - failCount++; + assertTrue(m.lookingAt()); - if (!m.group().equals(m.group(0))) - failCount++; + assertEquals(m.group(), m.group(0)); m = p.matcher(toSupplementaries("zzzabccczzzabcczzzabccczzz")); - if (m.lookingAt()) - failCount++; - - report("Looking At"); + assertFalse(m.lookingAt()); } /** * A basic sanity test of Matcher.matches(). */ - private static void matchesTest() throws Exception { + @Test + public static void matchesTest() { // matches() Pattern p = Pattern.compile("ulb(c*)"); Matcher m = p.matcher("ulbcccccc"); - if (!m.matches()) - failCount++; + assertTrue(m.matches()); // find() but not matches() m.reset("zzzulbcccccc"); - if (m.matches()) - failCount++; + assertFalse(m.matches()); // lookingAt() but not matches() m.reset("ulbccccccdef"); - if (m.matches()) - failCount++; + assertFalse(m.matches()); // matches() p = Pattern.compile("a|ad"); m = p.matcher("ad"); - if (!m.matches()) - failCount++; + assertTrue(m.matches()); // Supplementary character test // matches() p = Pattern.compile(toSupplementaries("ulb(c*)")); m = p.matcher(toSupplementaries("ulbcccccc")); - if (!m.matches()) - failCount++; + assertTrue(m.matches()); // find() but not matches() m.reset(toSupplementaries("zzzulbcccccc")); - if (m.matches()) - failCount++; + assertFalse(m.matches()); // lookingAt() but not matches() m.reset(toSupplementaries("ulbccccccdef")); - if (m.matches()) - failCount++; + assertFalse(m.matches()); // matches() p = Pattern.compile(toSupplementaries("a|ad")); m = p.matcher(toSupplementaries("ad")); - if (!m.matches()) - failCount++; - - report("Matches"); + assertTrue(m.matches()); } /** * A basic sanity test of Pattern.matches(). */ - private static void patternMatchesTest() throws Exception { + @Test + public static void patternMatchesTest() { // matches() - if (!Pattern.matches(toSupplementaries("ulb(c*)"), - toSupplementaries("ulbcccccc"))) - failCount++; + assertTrue(Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbcccccc"))); // find() but not matches() - if (Pattern.matches(toSupplementaries("ulb(c*)"), - toSupplementaries("zzzulbcccccc"))) - failCount++; + assertFalse(Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("zzzulbcccccc"))); // lookingAt() but not matches() - if (Pattern.matches(toSupplementaries("ulb(c*)"), - toSupplementaries("ulbccccccdef"))) - failCount++; + assertFalse(Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbccccccdef"))); // Supplementary character test // matches() - if (!Pattern.matches(toSupplementaries("ulb(c*)"), - toSupplementaries("ulbcccccc"))) - failCount++; + assertTrue(Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbcccccc"))); // find() but not matches() - if (Pattern.matches(toSupplementaries("ulb(c*)"), - toSupplementaries("zzzulbcccccc"))) - failCount++; + assertFalse(Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("zzzulbcccccc"))); // lookingAt() but not matches() - if (Pattern.matches(toSupplementaries("ulb(c*)"), - toSupplementaries("ulbccccccdef"))) - failCount++; - - report("Pattern Matches"); + assertFalse(Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbccccccdef"))); } /** @@ -2678,50 +2222,42 @@ * to match sequences that are not explicitly specified in the * pattern when they are considered equivalent by the Unicode Standard. */ - private static void ceTest() throws Exception { + @Test + public static void ceTest() { // Decomposed char outside char classes Pattern p = Pattern.compile("testa\u030a", Pattern.CANON_EQ); Matcher m = p.matcher("test\u00e5"); - if (!m.matches()) - failCount++; + assertTrue(m.matches()); m.reset("testa\u030a"); - if (!m.matches()) - failCount++; + assertTrue(m.matches()); // Composed char outside char classes p = Pattern.compile("test\u00e5", Pattern.CANON_EQ); m = p.matcher("test\u00e5"); - if (!m.matches()) - failCount++; + assertTrue(m.matches()); m.reset("testa\u030a"); - if (!m.find()) - failCount++; + assertTrue(m.find()); // Decomposed char inside a char class p = Pattern.compile("test[abca\u030a]", Pattern.CANON_EQ); m = p.matcher("test\u00e5"); - if (!m.find()) - failCount++; + assertTrue(m.find()); m.reset("testa\u030a"); - if (!m.find()) - failCount++; + assertTrue(m.find()); // Composed char inside a char class p = Pattern.compile("test[abc\u00e5def\u00e0]", Pattern.CANON_EQ); m = p.matcher("test\u00e5"); - if (!m.find()) - failCount++; + assertTrue(m.find()); m.reset("testa\u0300"); - if (!m.find()) - failCount++; + assertTrue(m.find()); m.reset("testa\u030a"); - if (!m.find()) - failCount++; + assertTrue(m.find()); // Marks that cannot legally change order and be equivalent p = Pattern.compile("testa\u0308\u0300", Pattern.CANON_EQ); @@ -2817,632 +2353,602 @@ // { "test\ud834\uddc0", "test\ud834\uddbc\ud834\udd6f", "m", true }, */ { "test\ud834\uddbc\ud834\udd6f", "test\ud834\uddbc\ud834\udd6f", "m", true }, - { "test\ud834\uddc0", "test\ud834\uddbc\ud834\udd6f", "m", true }, + //{ "test\ud834\uddc0", "test\ud834\uddbc\ud834\udd6f", "m", true }, //problem { "test\ud834\uddc0", "test\ud834\uddc0", "m", true }, - { "test\ud834\uddbc\ud834\udd6f", "test\ud834\uddc0", "m", true }, + //{ "test\ud834\uddbc\ud834\udd6f", "test\ud834\uddc0", "m", true }, //problem }; - int failCount = 0; for (Object[] d : data) { String pn = (String)d[0]; String tt = (String)d[1]; - boolean isFind = "f".equals(((String)d[2])); + boolean isFind = "f".equals((d[2])); boolean expected = (boolean)d[3]; boolean ret = isFind ? Pattern.compile(pn, Pattern.CANON_EQ).matcher(tt).find() : Pattern.compile(pn, Pattern.CANON_EQ).matcher(tt).matches(); if (ret != expected) { - failCount++; - continue; + fail("pn: " + pn + "\ntt: " + tt + "\nexpected: " + expected + "\nret: " + ret); } } - report("Canonical Equivalence"); } /** * A basic sanity test of Matcher.replaceAll(). */ - private static void globalSubstitute() throws Exception { + @Test + public static void globalSubstitute() { // Global substitution with a literal Pattern p = Pattern.compile("(ab)(c*)"); Matcher m = p.matcher("abccczzzabcczzzabccc"); - if (!m.replaceAll("test").equals("testzzztestzzztest")) - failCount++; + assertEquals(m.replaceAll("test"), "testzzztestzzztest"); m.reset("zzzabccczzzabcczzzabccczzz"); - if (!m.replaceAll("test").equals("zzztestzzztestzzztestzzz")) - failCount++; + assertEquals(m.replaceAll("test"), "zzztestzzztestzzztestzzz"); // Global substitution with groups m.reset("zzzabccczzzabcczzzabccczzz"); String result = m.replaceAll("$1"); - if (!result.equals("zzzabzzzabzzzabzzz")) - failCount++; + assertEquals(result, "zzzabzzzabzzzabzzz"); // Supplementary character test // Global substitution with a literal p = Pattern.compile(toSupplementaries("(ab)(c*)")); m = p.matcher(toSupplementaries("abccczzzabcczzzabccc")); - if (!m.replaceAll(toSupplementaries("test")). - equals(toSupplementaries("testzzztestzzztest"))) - failCount++; + assertEquals(m.replaceAll(toSupplementaries("test")), + toSupplementaries("testzzztestzzztest")); m.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); - if (!m.replaceAll(toSupplementaries("test")). - equals(toSupplementaries("zzztestzzztestzzztestzzz"))) - failCount++; + assertEquals(m.replaceAll(toSupplementaries("test")), + toSupplementaries("zzztestzzztestzzztestzzz")); // Global substitution with groups m.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); result = m.replaceAll("$1"); - if (!result.equals(toSupplementaries("zzzabzzzabzzzabzzz"))) - failCount++; - - report("Global Substitution"); + assertEquals(result,toSupplementaries("zzzabzzzabzzzabzzz")); } /** * Tests the usage of Matcher.appendReplacement() with literal * and group substitutions. */ - private static void stringbufferSubstitute() throws Exception { + @Test + public static void stringBufferSubstituteLiteral() { // SB substitution with literal - String blah = "zzzblahzzz"; - Pattern p = Pattern.compile("blah"); - Matcher m = p.matcher(blah); - StringBuffer result = new StringBuffer(); - try { - m.appendReplacement(result, "blech"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = "zzzblahzzz"; + final Pattern p = Pattern.compile("blah"); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); + + assertThrows(IllegalStateException.class, () -> m.appendReplacement(result, "blech")); + m.find(); m.appendReplacement(result, "blech"); - if (!result.toString().equals("zzzblech")) - failCount++; + assertEquals(result.toString(), "zzzblech"); m.appendTail(result); - if (!result.toString().equals("zzzblechzzz")) - failCount++; + assertEquals(result.toString(), "zzzblechzzz"); + + } + @Test + public static void stringBufferSubtituteWithGroups() { // SB substitution with groups - blah = "zzzabcdzzz"; - p = Pattern.compile("(ab)(cd)*"); - m = p.matcher(blah); - result = new StringBuffer(); - try { - m.appendReplacement(result, "$1"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = "zzzabcdzzz"; + final Pattern p = Pattern.compile("(ab)(cd)*"); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); + assertThrows(IllegalStateException.class, () -> m.appendReplacement(result, "$1")); m.find(); m.appendReplacement(result, "$1"); - if (!result.toString().equals("zzzab")) - failCount++; + assertEquals(result.toString(), "zzzab"); m.appendTail(result); - if (!result.toString().equals("zzzabzzz")) - failCount++; + assertEquals(result.toString(), "zzzabzzz"); + } + @Test + public static void stringBufferThreeSubstitution() { // SB substitution with 3 groups - blah = "zzzabcdcdefzzz"; - p = Pattern.compile("(ab)(cd)*(ef)"); - m = p.matcher(blah); - result = new StringBuffer(); - try { - m.appendReplacement(result, "$1w$2w$3"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = "zzzabcdcdefzzz"; + final Pattern p = Pattern.compile("(ab)(cd)*(ef)"); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); + assertThrows(IllegalStateException.class, () -> m.appendReplacement(result, "$1w$2w$3")); m.find(); m.appendReplacement(result, "$1w$2w$3"); - if (!result.toString().equals("zzzabwcdwef")) - failCount++; + assertEquals(result.toString(), "zzzabwcdwef"); m.appendTail(result); - if (!result.toString().equals("zzzabwcdwefzzz")) - failCount++; + assertEquals(result.toString(), "zzzabwcdwefzzz"); + + } + @Test + public static void stringBufferSubstituteGroupsThreeMatches() { // SB substitution with groups and three matches // skipping middle match - blah = "zzzabcdzzzabcddzzzabcdzzz"; - p = Pattern.compile("(ab)(cd*)"); - m = p.matcher(blah); - result = new StringBuffer(); - try { - m.appendReplacement(result, "$1"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = "zzzabcdzzzabcddzzzabcdzzz"; + final Pattern p = Pattern.compile("(ab)(cd*)"); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); + assertThrows(IllegalStateException.class, () -> m.appendReplacement(result, "$1")); + m.find(); m.appendReplacement(result, "$1"); - if (!result.toString().equals("zzzab")) - failCount++; + assertEquals(result.toString(), "zzzab"); m.find(); m.find(); m.appendReplacement(result, "$2"); - if (!result.toString().equals("zzzabzzzabcddzzzcd")) - failCount++; + assertEquals(result.toString(), "zzzabzzzabcddzzzcd"); m.appendTail(result); - if (!result.toString().equals("zzzabzzzabcddzzzcdzzz")) - failCount++; + assertEquals(result.toString(), "zzzabzzzabcddzzzcdzzz"); + + } + + @Test + public static void stringBufferEscapedDollar() { // Check to make sure escaped $ is ignored - blah = "zzzabcdcdefzzz"; - p = Pattern.compile("(ab)(cd)*(ef)"); - m = p.matcher(blah); - result = new StringBuffer(); + String blah = "zzzabcdcdefzzz"; + Pattern p = Pattern.compile("(ab)(cd)*(ef)"); + Matcher m = p.matcher(blah); + StringBuffer result = new StringBuffer(); m.find(); m.appendReplacement(result, "$1w\\$2w$3"); - if (!result.toString().equals("zzzabw$2wef")) - failCount++; + assertEquals(result.toString(), "zzzabw$2wef"); m.appendTail(result); - if (!result.toString().equals("zzzabw$2wefzzz")) - failCount++; + assertEquals(result.toString(), "zzzabw$2wefzzz"); + } + @Test + public static void stringBufferNonExistentGroup() { // Check to make sure a reference to nonexistent group causes error - blah = "zzzabcdcdefzzz"; - p = Pattern.compile("(ab)(cd)*(ef)"); - m = p.matcher(blah); - result = new StringBuffer(); + final String blah = "zzzabcdcdefzzz"; + final Pattern p = Pattern.compile("(ab)(cd)*(ef)"); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); m.find(); - try { - m.appendReplacement(result, "$1w$5w$3"); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Correct result - } + assertThrows(IndexOutOfBoundsException.class, + () -> m.appendReplacement(result, "$1w$5w$3")); + } + + @Test + public static void stringBufferCheckDoubleDigitGroupReferences() { // Check double digit group references - blah = "zzz123456789101112zzz"; - p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); - m = p.matcher(blah); - result = new StringBuffer(); + String blah = "zzz123456789101112zzz"; + Pattern p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + Matcher m = p.matcher(blah); + StringBuffer result = new StringBuffer(); m.find(); m.appendReplacement(result, "$1w$11w$3"); - if (!result.toString().equals("zzz1w11w3")) - failCount++; + assertEquals(result.toString(), "zzz1w11w3"); + + } + @Test + public static void stringBufferBackoff() { // Check to make sure it backs off $15 to $1 if only three groups - blah = "zzzabcdcdefzzz"; - p = Pattern.compile("(ab)(cd)*(ef)"); - m = p.matcher(blah); - result = new StringBuffer(); + String blah = "zzzabcdcdefzzz"; + Pattern p = Pattern.compile("(ab)(cd)*(ef)"); + Matcher m = p.matcher(blah); + StringBuffer result = new StringBuffer(); m.find(); m.appendReplacement(result, "$1w$15w$3"); - if (!result.toString().equals("zzzabwab5wef")) - failCount++; - + assertEquals(result.toString(), "zzzabwab5wef"); + } + @Test + public static void stringBufferSupplementaryCharacter(){ // Supplementary character test // SB substitution with literal - blah = toSupplementaries("zzzblahzzz"); - p = Pattern.compile(toSupplementaries("blah")); - m = p.matcher(blah); - result = new StringBuffer(); - try { - m.appendReplacement(result, toSupplementaries("blech")); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = toSupplementaries("zzzblahzzz"); + final Pattern p = Pattern.compile(toSupplementaries("blah")); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); + assertThrows(IllegalStateException.class, + () -> m.appendReplacement(result, toSupplementaries("blech"))); m.find(); m.appendReplacement(result, toSupplementaries("blech")); - if (!result.toString().equals(toSupplementaries("zzzblech"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzblech")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzblechzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzblechzzz")); + } + @Test + public static void stringBufferSubstitutionWithGroups() { // SB substitution with groups - blah = toSupplementaries("zzzabcdzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*")); - m = p.matcher(blah); - result = new StringBuffer(); - try { - m.appendReplacement(result, "$1"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = toSupplementaries("zzzabcdzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*")); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); + assertThrows(IllegalStateException.class, + () -> m.appendReplacement(result, "$1")); m.find(); m.appendReplacement(result, "$1"); - if (!result.toString().equals(toSupplementaries("zzzab"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzab")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzabzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabzzz")); + } + @Test + public static void stringBufferSubstituteWithThreeGroups() { // SB substitution with 3 groups - blah = toSupplementaries("zzzabcdcdefzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); - m = p.matcher(blah); - result = new StringBuffer(); - try { - m.appendReplacement(result, toSupplementaries("$1w$2w$3")); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = toSupplementaries("zzzabcdcdefzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); + assertThrows(IllegalStateException.class, + () -> m.appendReplacement(result, toSupplementaries("$1w$2w$3"))); + m.find(); m.appendReplacement(result, toSupplementaries("$1w$2w$3")); - if (!result.toString().equals(toSupplementaries("zzzabwcdwef"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabwcdwef")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzabwcdwefzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabwcdwefzzz")); + } + @Test + public static void stringBufferWithGroupsAndThreeMatches() { // SB substitution with groups and three matches // skipping middle match - blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd*)")); - m = p.matcher(blah); - result = new StringBuffer(); - try { - m.appendReplacement(result, "$1"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd*)")); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); + assertThrows(IllegalStateException.class, () -> + m.appendReplacement(result, "$1")); + m.find(); m.appendReplacement(result, "$1"); - if (!result.toString().equals(toSupplementaries("zzzab"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzab")); m.find(); m.find(); m.appendReplacement(result, "$2"); - if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcd"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabzzzabcddzzzcd")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcdzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabzzzabcddzzzcdzzz")); + } + @Test + public static void stringBufferEnsureDollarIgnored() { // Check to make sure escaped $ is ignored - blah = toSupplementaries("zzzabcdcdefzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); - m = p.matcher(blah); - result = new StringBuffer(); + String blah = toSupplementaries("zzzabcdcdefzzz"); + Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + Matcher m = p.matcher(blah); + StringBuffer result = new StringBuffer(); m.find(); m.appendReplacement(result, toSupplementaries("$1w\\$2w$3")); - if (!result.toString().equals(toSupplementaries("zzzabw$2wef"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabw$2wef")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzabw$2wefzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabw$2wefzzz")); + } + @Test + public static void stringBufferCheckNonexistentGroupReference() { // Check to make sure a reference to nonexistent group causes error - blah = toSupplementaries("zzzabcdcdefzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); - m = p.matcher(blah); - result = new StringBuffer(); + final String blah = toSupplementaries("zzzabcdcdefzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + final Matcher m = p.matcher(blah); + final StringBuffer result = new StringBuffer(); m.find(); - try { - m.appendReplacement(result, toSupplementaries("$1w$5w$3")); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Correct result - } + assertThrows(IndexOutOfBoundsException.class, () -> + m.appendReplacement(result, toSupplementaries("$1w$5w$3"))); + } + @Test + public static void stringBufferCheckSupplementalDoubleDigitGroupReferences() { // Check double digit group references - blah = toSupplementaries("zzz123456789101112zzz"); - p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); - m = p.matcher(blah); - result = new StringBuffer(); + String blah = toSupplementaries("zzz123456789101112zzz"); + Pattern p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + Matcher m = p.matcher(blah); + StringBuffer result = new StringBuffer(); m.find(); m.appendReplacement(result, toSupplementaries("$1w$11w$3")); - if (!result.toString().equals(toSupplementaries("zzz1w11w3"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzz1w11w3")); + } + @Test + public static void stringBufferBackoffSupplemental() { // Check to make sure it backs off $15 to $1 if only three groups - blah = toSupplementaries("zzzabcdcdefzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); - m = p.matcher(blah); - result = new StringBuffer(); + String blah = toSupplementaries("zzzabcdcdefzzz"); + Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + Matcher m = p.matcher(blah); + StringBuffer result = new StringBuffer(); m.find(); m.appendReplacement(result, toSupplementaries("$1w$15w$3")); - if (!result.toString().equals(toSupplementaries("zzzabwab5wef"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabwab5wef")); + } + @Test + public static void stringBufferCheckAppendException() { // Check nothing has been appended into the output buffer if // the replacement string triggers IllegalArgumentException. - p = Pattern.compile("(abc)"); - m = p.matcher("abcd"); - result = new StringBuffer(); + Pattern p = Pattern.compile("(abc)"); + Matcher m = p.matcher("abcd"); + StringBuffer result = new StringBuffer(); m.find(); - try { - m.appendReplacement(result, ("xyz$g")); - failCount++; - } catch (IllegalArgumentException iae) { - if (result.length() != 0) - failCount++; - } + expectThrows(IllegalArgumentException.class, + () -> m.appendReplacement(result, ("xyz$g"))); + assertEquals(result.length(), 0); - report("SB Substitution"); } - /** * Tests the usage of Matcher.appendReplacement() with literal * and group substitutions. */ - private static void stringbuilderSubstitute() throws Exception { + @Test + public static void stringBuilderSubstitutionWithLiteral() { // SB substitution with literal - String blah = "zzzblahzzz"; - Pattern p = Pattern.compile("blah"); - Matcher m = p.matcher(blah); - StringBuilder result = new StringBuilder(); - try { - m.appendReplacement(result, "blech"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = "zzzblahzzz"; + final Pattern p = Pattern.compile("blah"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); + assertThrows(IllegalStateException.class, () -> + m.appendReplacement(result, "blech")); + m.find(); m.appendReplacement(result, "blech"); - if (!result.toString().equals("zzzblech")) - failCount++; + assertEquals(result.toString(), "zzzblech"); m.appendTail(result); - if (!result.toString().equals("zzzblechzzz")) - failCount++; + assertEquals(result.toString(), "zzzblechzzz"); + } + @Test + public static void stringBuilderSubstitutionWithGroups() { // SB substitution with groups - blah = "zzzabcdzzz"; - p = Pattern.compile("(ab)(cd)*"); - m = p.matcher(blah); - result = new StringBuilder(); - try { - m.appendReplacement(result, "$1"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = "zzzabcdzzz"; + final Pattern p = Pattern.compile("(ab)(cd)*"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); + assertThrows(IllegalStateException.class, () -> + m.appendReplacement(result, "$1")); m.find(); m.appendReplacement(result, "$1"); - if (!result.toString().equals("zzzab")) - failCount++; + assertEquals(result.toString(), "zzzab"); m.appendTail(result); - if (!result.toString().equals("zzzabzzz")) - failCount++; + assertEquals(result.toString(), "zzzabzzz"); + } + @Test + public static void stringBuilderSubstitutionWithThreeGroups() { // SB substitution with 3 groups - blah = "zzzabcdcdefzzz"; - p = Pattern.compile("(ab)(cd)*(ef)"); - m = p.matcher(blah); - result = new StringBuilder(); - try { - m.appendReplacement(result, "$1w$2w$3"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = "zzzabcdcdefzzz"; + final Pattern p = Pattern.compile("(ab)(cd)*(ef)"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); + assertThrows(IllegalStateException.class, () -> + m.appendReplacement(result, "$1w$2w$3")); + m.find(); m.appendReplacement(result, "$1w$2w$3"); - if (!result.toString().equals("zzzabwcdwef")) - failCount++; + assertEquals(result.toString(), "zzzabwcdwef"); m.appendTail(result); - if (!result.toString().equals("zzzabwcdwefzzz")) - failCount++; + assertEquals(result.toString(), "zzzabwcdwefzzz"); + } + @Test + public static void stringBuilderSubstitutionThreeMatch() { // SB substitution with groups and three matches // skipping middle match - blah = "zzzabcdzzzabcddzzzabcdzzz"; - p = Pattern.compile("(ab)(cd*)"); - m = p.matcher(blah); - result = new StringBuilder(); - try { - m.appendReplacement(result, "$1"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = "zzzabcdzzzabcddzzzabcdzzz"; + final Pattern p = Pattern.compile("(ab)(cd*)"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); + assertThrows(IllegalStateException.class, () -> + m.appendReplacement(result, "$1")); m.find(); m.appendReplacement(result, "$1"); - if (!result.toString().equals("zzzab")) - failCount++; + assertEquals(result.toString(), "zzzab"); m.find(); m.find(); m.appendReplacement(result, "$2"); - if (!result.toString().equals("zzzabzzzabcddzzzcd")) - failCount++; + assertEquals(result.toString(), "zzzabzzzabcddzzzcd"); m.appendTail(result); - if (!result.toString().equals("zzzabzzzabcddzzzcdzzz")) - failCount++; + assertEquals(result.toString(), "zzzabzzzabcddzzzcdzzz"); + } + @Test + public static void stringBuilderSubtituteCheckEscapedDollar() { // Check to make sure escaped $ is ignored - blah = "zzzabcdcdefzzz"; - p = Pattern.compile("(ab)(cd)*(ef)"); - m = p.matcher(blah); - result = new StringBuilder(); + final String blah = "zzzabcdcdefzzz"; + final Pattern p = Pattern.compile("(ab)(cd)*(ef)"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); m.find(); m.appendReplacement(result, "$1w\\$2w$3"); - if (!result.toString().equals("zzzabw$2wef")) - failCount++; + assertEquals(result.toString(), "zzzabw$2wef"); m.appendTail(result); - if (!result.toString().equals("zzzabw$2wefzzz")) - failCount++; + assertEquals(result.toString(), "zzzabw$2wefzzz"); + } + @Test + public static void stringBuilderNonexistentGroupError() { // Check to make sure a reference to nonexistent group causes error - blah = "zzzabcdcdefzzz"; - p = Pattern.compile("(ab)(cd)*(ef)"); - m = p.matcher(blah); - result = new StringBuilder(); + final String blah = "zzzabcdcdefzzz"; + final Pattern p = Pattern.compile("(ab)(cd)*(ef)"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); m.find(); - try { - m.appendReplacement(result, "$1w$5w$3"); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Correct result - } + assertThrows(IndexOutOfBoundsException.class, () -> + m.appendReplacement(result, "$1w$5w$3")); + } + @Test + public static void stringBuilderDoubleDigitGroupReferences() { // Check double digit group references - blah = "zzz123456789101112zzz"; - p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); - m = p.matcher(blah); - result = new StringBuilder(); + final String blah = "zzz123456789101112zzz"; + final Pattern p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); m.find(); m.appendReplacement(result, "$1w$11w$3"); - if (!result.toString().equals("zzz1w11w3")) - failCount++; + assertEquals(result.toString(), "zzz1w11w3"); + } + @Test + public static void stringBuilderCheckBackoff() { // Check to make sure it backs off $15 to $1 if only three groups - blah = "zzzabcdcdefzzz"; - p = Pattern.compile("(ab)(cd)*(ef)"); - m = p.matcher(blah); - result = new StringBuilder(); + final String blah = "zzzabcdcdefzzz"; + final Pattern p = Pattern.compile("(ab)(cd)*(ef)"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); m.find(); m.appendReplacement(result, "$1w$15w$3"); - if (!result.toString().equals("zzzabwab5wef")) - failCount++; - + assertEquals(result.toString(), "zzzabwab5wef"); + } + @Test + public static void stringBuilderSupplementalLiteralSubstitution() { // Supplementary character test // SB substitution with literal - blah = toSupplementaries("zzzblahzzz"); - p = Pattern.compile(toSupplementaries("blah")); - m = p.matcher(blah); - result = new StringBuilder(); - try { - m.appendReplacement(result, toSupplementaries("blech")); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = toSupplementaries("zzzblahzzz"); + final Pattern p = Pattern.compile(toSupplementaries("blah")); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); + assertThrows(IllegalStateException.class, + () -> m.appendReplacement(result, toSupplementaries("blech"))); m.find(); m.appendReplacement(result, toSupplementaries("blech")); - if (!result.toString().equals(toSupplementaries("zzzblech"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzblech")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzblechzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzblechzzz")); + } + @Test + public static void stringBuilderSupplementalSubstitutionWithGroups() { // SB substitution with groups - blah = toSupplementaries("zzzabcdzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*")); - m = p.matcher(blah); - result = new StringBuilder(); - try { - m.appendReplacement(result, "$1"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = toSupplementaries("zzzabcdzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*")); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); + assertThrows(IllegalStateException.class, + () -> m.appendReplacement(result, "$1")); m.find(); m.appendReplacement(result, "$1"); - if (!result.toString().equals(toSupplementaries("zzzab"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzab")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzabzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabzzz")); + } + @Test + public static void stringBuilderSupplementalSubstitutionThreeGroups() { // SB substitution with 3 groups - blah = toSupplementaries("zzzabcdcdefzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); - m = p.matcher(blah); - result = new StringBuilder(); - try { - m.appendReplacement(result, toSupplementaries("$1w$2w$3")); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = toSupplementaries("zzzabcdcdefzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); + assertThrows(IllegalStateException.class, () -> + m.appendReplacement(result, toSupplementaries("$1w$2w$3"))); m.find(); m.appendReplacement(result, toSupplementaries("$1w$2w$3")); - if (!result.toString().equals(toSupplementaries("zzzabwcdwef"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabwcdwef")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzabwcdwefzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabwcdwefzzz")); + } + @Test + public static void stringBuilderSubstitutionSupplementalSkipMiddleThreeMatch() { // SB substitution with groups and three matches // skipping middle match - blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd*)")); - m = p.matcher(blah); - result = new StringBuilder(); - try { - m.appendReplacement(result, "$1"); - failCount++; - } catch (IllegalStateException e) { - } + final String blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd*)")); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); + assertThrows(IllegalStateException.class, () -> + m.appendReplacement(result, "$1")); m.find(); m.appendReplacement(result, "$1"); - if (!result.toString().equals(toSupplementaries("zzzab"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzab")); m.find(); m.find(); m.appendReplacement(result, "$2"); - if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcd"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabzzzabcddzzzcd")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcdzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabzzzabcddzzzcdzzz")); + } + @Test + public static void stringBuilderSupplementalEscapedDollar() { // Check to make sure escaped $ is ignored - blah = toSupplementaries("zzzabcdcdefzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); - m = p.matcher(blah); - result = new StringBuilder(); + final String blah = toSupplementaries("zzzabcdcdefzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); m.find(); m.appendReplacement(result, toSupplementaries("$1w\\$2w$3")); - if (!result.toString().equals(toSupplementaries("zzzabw$2wef"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabw$2wef")); m.appendTail(result); - if (!result.toString().equals(toSupplementaries("zzzabw$2wefzzz"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabw$2wefzzz")); + } + @Test + public static void stringBuilderSupplementalNonExistentGroupError() { // Check to make sure a reference to nonexistent group causes error - blah = toSupplementaries("zzzabcdcdefzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); - m = p.matcher(blah); - result = new StringBuilder(); + final String blah = toSupplementaries("zzzabcdcdefzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); m.find(); - try { - m.appendReplacement(result, toSupplementaries("$1w$5w$3")); - failCount++; - } catch (IndexOutOfBoundsException ioobe) { - // Correct result - } + assertThrows(IndexOutOfBoundsException.class, () -> + m.appendReplacement(result, toSupplementaries("$1w$5w$3"))); + } + + @Test + public static void stringBuilderSupplementalCheckDoubleDigitGroupReferences() { // Check double digit group references - blah = toSupplementaries("zzz123456789101112zzz"); - p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); - m = p.matcher(blah); - result = new StringBuilder(); + final String blah = toSupplementaries("zzz123456789101112zzz"); + final Pattern p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); m.find(); m.appendReplacement(result, toSupplementaries("$1w$11w$3")); - if (!result.toString().equals(toSupplementaries("zzz1w11w3"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzz1w11w3")); + } + @Test + public static void stringBuilderSupplementalCheckBackoff() { // Check to make sure it backs off $15 to $1 if only three groups - blah = toSupplementaries("zzzabcdcdefzzz"); - p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); - m = p.matcher(blah); - result = new StringBuilder(); + final String blah = toSupplementaries("zzzabcdcdefzzz"); + final Pattern p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + final Matcher m = p.matcher(blah); + final StringBuilder result = new StringBuilder(); m.find(); m.appendReplacement(result, toSupplementaries("$1w$15w$3")); - if (!result.toString().equals(toSupplementaries("zzzabwab5wef"))) - failCount++; + assertEquals(result.toString(), toSupplementaries("zzzabwab5wef")); + } + + @Test + public static void stringBuilderCheckIllegalArgumentException() { // Check nothing has been appended into the output buffer if // the replacement string triggers IllegalArgumentException. - p = Pattern.compile("(abc)"); - m = p.matcher("abcd"); - result = new StringBuilder(); - m.find(); - try { - m.appendReplacement(result, ("xyz$g")); - failCount++; - } catch (IllegalArgumentException iae) { - if (result.length() != 0) - failCount++; - } - report("SB Substitution 2"); + final Pattern p = Pattern.compile("(abc)"); + final Matcher m = p.matcher("abcd"); + final StringBuilder result = new StringBuilder(); + m.find(); + assertThrows(IllegalArgumentException.class, () -> + m.appendReplacement(result, ("xyz$g"))); + assertEquals(result.length(), 0); } /* @@ -3453,19 +2959,20 @@ * random group + random string + random group. * The results are checked for correctness. */ - private static void substitutionBasher() { + @Test + public static void substitutionBasher() { for (int runs = 0; runs<1000; runs++) { // Create a base string to work in int leadingChars = generator.nextInt(10); - StringBuffer baseBuffer = new StringBuffer(100); + StringBuilder baseBuffer = new StringBuilder(100); String leadingString = getRandomAlphaString(leadingChars); baseBuffer.append(leadingString); // Create 5 groups of random number of random chars // Create the string to substitute // Create the pattern string to search for - StringBuffer bufferToSub = new StringBuffer(25); - StringBuffer bufferToPat = new StringBuffer(50); + StringBuilder bufferToSub = new StringBuilder(25); + StringBuilder bufferToPat = new StringBuilder(50); String[] groups = new String[5]; for(int i=0; i<5; i++) { int aGroupSize = generator.nextInt(5)+1; @@ -3502,33 +3009,28 @@ // Construct a replacement string with : // random group + random string + random group - StringBuffer bufferToRep = new StringBuffer(); + StringBuilder bufferToRep = new StringBuilder(); int groupIndex1 = generator.nextInt(5); - bufferToRep.append("$" + (groupIndex1 + 1)); + bufferToRep.append("$").append(groupIndex1 + 1); String randomMidString = getRandomAlphaString(5); bufferToRep.append(randomMidString); int groupIndex2 = generator.nextInt(5); - bufferToRep.append("$" + (groupIndex2 + 1)); + bufferToRep.append("$").append(groupIndex2 + 1); String replacement = bufferToRep.toString(); // Do the replacement String result = m.replaceAll(replacement); // Construct expected result - StringBuffer bufferToRes = new StringBuffer(); - bufferToRes.append(leadingString); - bufferToRes.append(groups[groupIndex1]); - bufferToRes.append(randomMidString); - bufferToRes.append(groups[groupIndex2]); - bufferToRes.append(trailingString); - String expectedResult = bufferToRes.toString(); + String expectedResult = leadingString + + groups[groupIndex1] + + randomMidString + + groups[groupIndex2] + + trailingString; // Check results - if (!result.equals(expectedResult)) - failCount++; + assertEquals(result, expectedResult); } - - report("Substitution Basher"); } /* @@ -3539,7 +3041,8 @@ * random group + random string + random group. * The results are checked for correctness. */ - private static void substitutionBasher2() { + @Test + public static void substitutionBasher2() { for (int runs = 0; runs<1000; runs++) { // Create a base string to work in int leadingChars = generator.nextInt(10); @@ -3590,32 +3093,26 @@ // random group + random string + random group StringBuilder bufferToRep = new StringBuilder(); int groupIndex1 = generator.nextInt(5); - bufferToRep.append("$" + (groupIndex1 + 1)); + bufferToRep.append("$").append(groupIndex1 + 1); String randomMidString = getRandomAlphaString(5); bufferToRep.append(randomMidString); int groupIndex2 = generator.nextInt(5); - bufferToRep.append("$" + (groupIndex2 + 1)); + bufferToRep.append("$").append(groupIndex2 + 1); String replacement = bufferToRep.toString(); // Do the replacement String result = m.replaceAll(replacement); // Construct expected result - StringBuilder bufferToRes = new StringBuilder(); - bufferToRes.append(leadingString); - bufferToRes.append(groups[groupIndex1]); - bufferToRes.append(randomMidString); - bufferToRes.append(groups[groupIndex2]); - bufferToRes.append(trailingString); - String expectedResult = bufferToRes.toString(); + String expectedResult = leadingString + + groups[groupIndex1] + + randomMidString + + groups[groupIndex2] + + trailingString; // Check results - if (!result.equals(expectedResult)) { - failCount++; - } + assertEquals(result, expectedResult); } - - report("Substitution Basher 2"); } /** @@ -3624,72 +3121,60 @@ * not in the file because the escapes should be be processed * by the Pattern class when the regex is compiled. */ - private static void escapes() throws Exception { + @Test + public static void escapes() { Pattern p = Pattern.compile("\\043"); Matcher m = p.matcher("#"); - if (!m.find()) - failCount++; + assertTrue(m.find()); p = Pattern.compile("\\x23"); m = p.matcher("#"); - if (!m.find()) - failCount++; + assertTrue(m.find()); p = Pattern.compile("\\u0023"); m = p.matcher("#"); - if (!m.find()) - failCount++; - - report("Escape sequences"); + assertTrue(m.find()); } /** * Checks the handling of blank input situations. These * tests are incompatible with my test file format. */ - private static void blankInput() throws Exception { + @Test + public static void blankInput() { Pattern p = Pattern.compile("abc", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher(""); - if (m.find()) - failCount++; + assertFalse(m.find()); p = Pattern.compile("a*", Pattern.CASE_INSENSITIVE); m = p.matcher(""); - if (!m.find()) - failCount++; + assertTrue(m.find()); p = Pattern.compile("abc"); m = p.matcher(""); - if (m.find()) - failCount++; + assertFalse(m.find()); p = Pattern.compile("a*"); m = p.matcher(""); - if (!m.find()) - failCount++; - - report("Blank input"); + assertTrue(m.find()); } /** * Tests the Boyer-Moore pattern matching of a character sequence * on randomly generated patterns. */ - private static void bm() throws Exception { + @Test + public static void bm() { doBnM('a'); - report("Boyer Moore (ASCII)"); doBnM(Character.MIN_SUPPLEMENTARY_CODE_POINT - 10); - report("Boyer Moore (Supplementary)"); } - private static void doBnM(int baseCharacter) throws Exception { - int achar=0; - + private static void doBnM(int baseCharacter) { for (int i=0; i<100; i++) { // Create a short pattern to search for int patternLength = generator.nextInt(7) + 4; - StringBuffer patternBuffer = new StringBuffer(patternLength); + StringBuilder patternBuffer = new StringBuilder(patternLength); String pattern; retry: for (;;) { for (int x=0; xy+)z+"), "xxxyyyzzz", "gname", @@ -4207,9 +3565,8 @@ "zzzDogzzzDogzzz"); // backref in Matcher & String - if (!"abcdefghij".replaceFirst("cd(?ef)gh", "${gn}").equals("abefij") || - !"abbbcbdbefgh".replaceAll("(?[a-e])b", "${gn}").equals("abcdefgh")) - failCount++; + assertTrue("abcdefghij".replaceFirst("cd(?ef)gh", "${gn}").equals("abefij") && + "abbbcbdbefgh".replaceAll("(?[a-e])b", "${gn}").equals("abcdefgh")); // negative checkExpectedFail("(?abc)(def)"); @@ -4217,55 +3574,57 @@ checkExpectedFail("(?<6groupnamestartswithdigit>abc)(def)"); checkExpectedFail("(?abc)(def)\\k"); checkExpectedFail("(?abc)(?def)\\k"); - checkExpectedIAE(Pattern.compile("(?abc)(def)").matcher("abcdef"), - "gnameX"); - checkExpectedNPE(Pattern.compile("(?abc)(def)").matcher("abcdef")); - report("NamedGroupCapture"); + + Matcher iaeMatcher = Pattern.compile("(?abc)(def)").matcher("abcdef"); + iaeMatcher.find(); + assertThrows(IllegalArgumentException.class, () -> iaeMatcher.group("gnameX")); + assertThrows(IllegalArgumentException.class, () -> iaeMatcher.start("gnameX")); + assertThrows(IllegalArgumentException.class, () -> iaeMatcher.start("gnameX")); + + Matcher npeMatcher = Pattern.compile("(?abc)(def)").matcher("abcdef"); + npeMatcher.find(); + assertThrows(NullPointerException.class, () -> npeMatcher.group(null)); + assertThrows(NullPointerException.class, () -> npeMatcher.start(null)); + assertThrows(NullPointerException.class, () -> npeMatcher.end(null)); } // This is for bug 6919132 - private static void nonBmpClassComplementTest() throws Exception { + @Test + public static void nonBmpClassComplementTest() { Pattern p = Pattern.compile("\\P{Lu}"); Matcher m = p.matcher(new String(new int[] {0x1d400}, 0, 1)); - if (m.find() && m.start() == 1) - failCount++; + assertFalse(m.find() && m.start() == 1); // from a unicode category p = Pattern.compile("\\P{Lu}"); m = p.matcher(new String(new int[] {0x1d400}, 0, 1)); - if (m.find()) - failCount++; - if (!m.hitEnd()) - failCount++; + assertFalse(m.find()); + assertTrue(m.hitEnd()); // block p = Pattern.compile("\\P{InMathematicalAlphanumericSymbols}"); m = p.matcher(new String(new int[] {0x1d400}, 0, 1)); - if (m.find() && m.start() == 1) - failCount++; + assertFalse(m.find() && m.start() == 1); p = Pattern.compile("\\P{sc=GRANTHA}"); m = p.matcher(new String(new int[] {0x11350}, 0, 1)); - if (m.find() && m.start() == 1) - failCount++; - - report("NonBmpClassComplement"); + assertFalse(m.find() && m.start() == 1); } - private static void unicodePropertiesTest() throws Exception { + @Test + public static void unicodePropertiesTest() { // different forms - if (!Pattern.compile("\\p{IsLu}").matcher("A").matches() || - !Pattern.compile("\\p{Lu}").matcher("A").matches() || - !Pattern.compile("\\p{gc=Lu}").matcher("A").matches() || - !Pattern.compile("\\p{general_category=Lu}").matcher("A").matches() || - !Pattern.compile("\\p{IsLatin}").matcher("B").matches() || - !Pattern.compile("\\p{sc=Latin}").matcher("B").matches() || - !Pattern.compile("\\p{script=Latin}").matcher("B").matches() || - !Pattern.compile("\\p{InBasicLatin}").matcher("c").matches() || - !Pattern.compile("\\p{blk=BasicLatin}").matcher("c").matches() || - !Pattern.compile("\\p{block=BasicLatin}").matcher("c").matches()) - failCount++; + assertFalse(!Pattern.compile("\\p{IsLu}").matcher("A").matches() || + !Pattern.compile("\\p{Lu}").matcher("A").matches() || + !Pattern.compile("\\p{gc=Lu}").matcher("A").matches() || + !Pattern.compile("\\p{general_category=Lu}").matcher("A").matches() || + !Pattern.compile("\\p{IsLatin}").matcher("B").matches() || + !Pattern.compile("\\p{sc=Latin}").matcher("B").matches() || + !Pattern.compile("\\p{script=Latin}").matcher("B").matches() || + !Pattern.compile("\\p{InBasicLatin}").matcher("c").matches() || + !Pattern.compile("\\p{blk=BasicLatin}").matcher("c").matches() || + !Pattern.compile("\\p{block=BasicLatin}").matcher("c").matches()); Matcher common = Pattern.compile("\\p{script=Common}").matcher(""); Matcher unknown = Pattern.compile("\\p{IsUnknown}").matcher(""); @@ -4292,14 +3651,11 @@ } else { m = Pattern.compile("\\p{Is" + script.name() + "}").matcher(str); } - if (!m.matches()) { - failCount++; - } + assertTrue(m.matches()); + Matcher other = (script == Character.UnicodeScript.COMMON)? unknown : common; other.reset(str); - if (other.matches()) { - failCount++; - } + assertFalse(other.matches()); lastSM = m; lastScript = script; @@ -4315,21 +3671,17 @@ } else { m = Pattern.compile("\\p{block=" + block.toString() + "}").matcher(str); } - if (!m.matches()) { - failCount++; - } + assertTrue(m.matches()); other = (block == Character.UnicodeBlock.BASIC_LATIN)? greek : latin; other.reset(str); - if (other.matches()) { - failCount++; - } + assertFalse(other.matches()); lastBM = m; lastBlock = block; } - report("unicodeProperties"); } - private static void unicodeHexNotationTest() throws Exception { + @Test + public static void unicodeHexNotationTest() { // negative checkExpectedFail("\\x{-23}"); @@ -4358,19 +3710,15 @@ (int) Character.toChars(cp)[0], (int) Character.toChars(cp)[1]); String hexCodePoint = "\\x{" + Integer.toHexString(cp) + "}"; - if (!Pattern.matches("A" + hexUTF16 + "B", s)) - failCount++; - if (!Pattern.matches("A[" + hexUTF16 + "]B", s)) - failCount++; - if (!Pattern.matches("A" + hexCodePoint + "B", s)) - failCount++; - if (!Pattern.matches("A[" + hexCodePoint + "]B", s)) - failCount++; + assertTrue(Pattern.matches("A" + hexUTF16 + "B", s)); + assertTrue(Pattern.matches("A[" + hexUTF16 + "]B", s)); + assertTrue(Pattern.matches("A" + hexCodePoint + "B", s)); + assertTrue(Pattern.matches("A[" + hexCodePoint + "]B", s)); } - report("unicodeHexNotation"); } - private static void unicodeClassesTest() throws Exception { + @Test + public static void unicodeClassesTest() { Matcher lower = Pattern.compile("\\p{Lower}").matcher(""); Matcher upper = Pattern.compile("\\p{Upper}").matcher(""); @@ -4501,26 +3849,22 @@ Character.PRIVATE_USE == type || Character.SURROGATE == type || Character.UNASSIGNED == type) != gcC.reset(str).matches()) { - failCount++; + fail(); } } // bounds/word align twoFindIndexes(" \u0180sherman\u0400 ", bound, 1, 10); - if (!bwbU.reset("\u0180sherman\u0400").matches()) - failCount++; + assertTrue(bwbU.reset("\u0180sherman\u0400").matches()); twoFindIndexes(" \u0180sh\u0345erman\u0400 ", bound, 1, 11); - if (!bwbU.reset("\u0180sh\u0345erman\u0400").matches()) - failCount++; + assertTrue(bwbU.reset("\u0180sh\u0345erman\u0400").matches()); twoFindIndexes(" \u0724\u0739\u0724 ", bound, 1, 4); - if (!bwbU.reset("\u0724\u0739\u0724").matches()) - failCount++; - if (!bwbEU.reset("\u0724\u0739\u0724").matches()) - failCount++; - report("unicodePredefinedClasses"); + assertTrue(bwbU.reset("\u0724\u0739\u0724").matches()); + assertTrue(bwbEU.reset("\u0724\u0739\u0724").matches()); } - private static void unicodeCharacterNameTest() throws Exception { + @Test + public static void unicodeCharacterNameTest() { for (int cp = 0; cp < Character.MAX_CODE_POINT; cp++) { if (!Character.isValidCodePoint(cp) || @@ -4529,14 +3873,10 @@ String str = new String(Character.toChars(cp)); // single String p = "\\N{" + Character.getName(cp) + "}"; - if (!Pattern.compile(p).matcher(str).matches()) { - failCount++; - } + assertTrue(Pattern.compile(p).matcher(str).matches()); // class[c] p = "[\\N{" + Character.getName(cp) + "}]"; - if (!Pattern.compile(p).matcher(str).matches()) { - failCount++; - } + assertTrue(Pattern.compile(p).matcher(str).matches()); } // range @@ -4547,39 +3887,33 @@ String str; for (int cp = start; cp < end; cp++) { str = new String(Character.toChars(cp)); - if (!Pattern.compile(p).matcher(str).matches()) { - failCount++; - } + assertTrue(Pattern.compile(p).matcher(str).matches()); } str = new String(Character.toChars(end + 10)); - if (Pattern.compile(p).matcher(str).matches()) { - failCount++; - } + assertFalse(Pattern.compile(p).matcher(str).matches()); } // slice for (int i = 0; i < 10; i++) { int n = generator.nextInt(256); int[] buf = new int[n]; - StringBuffer sb = new StringBuffer(1024); + StringBuilder sb = new StringBuilder(1024); for (int j = 0; j < n; j++) { int cp = generator.nextInt(1000); if (!Character.isValidCodePoint(cp) || Character.getType(cp) == Character.UNASSIGNED) cp = 0x4e00; // just use 4e00 - sb.append("\\N{" + Character.getName(cp) + "}"); + sb.append("\\N{").append(Character.getName(cp)).append("}"); buf[j] = cp; } String p = sb.toString(); String str = new String(buf, 0, buf.length); - if (!Pattern.compile(p).matcher(str).matches()) { - failCount++; - } + assertTrue(Pattern.compile(p).matcher(str).matches()); } - report("unicodeCharacterName"); } - private static void horizontalAndVerticalWSTest() throws Exception { + @Test + public static void horizontalAndVerticalWSTest() { String hws = new String (new char[] { 0x09, 0x20, 0xa0, 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, @@ -4587,105 +3921,92 @@ 0x202f, 0x205f, 0x3000 }); String vws = new String (new char[] { 0x0a, 0x0b, 0x0c, 0x0d, 0x85, 0x2028, 0x2029 }); - if (!Pattern.compile("\\h+").matcher(hws).matches() || - !Pattern.compile("[\\h]+").matcher(hws).matches()) - failCount++; - if (Pattern.compile("\\H").matcher(hws).find() || - Pattern.compile("[\\H]").matcher(hws).find()) - failCount++; - if (!Pattern.compile("\\v+").matcher(vws).matches() || - !Pattern.compile("[\\v]+").matcher(vws).matches()) - failCount++; - if (Pattern.compile("\\V").matcher(vws).find() || - Pattern.compile("[\\V]").matcher(vws).find()) - failCount++; + assertTrue(Pattern.compile("\\h+").matcher(hws).matches() && + Pattern.compile("[\\h]+").matcher(hws).matches()); + assertTrue(!Pattern.compile("\\H").matcher(hws).find() && + !Pattern.compile("[\\H]").matcher(hws).find()); + assertTrue(Pattern.compile("\\v+").matcher(vws).matches() && + Pattern.compile("[\\v]+").matcher(vws).matches()); + assertTrue(!Pattern.compile("\\V").matcher(vws).find() && + !Pattern.compile("[\\V]").matcher(vws).find()); String prefix = "abcd"; String suffix = "efgh"; String ng = "A"; for (int i = 0; i < hws.length(); i++) { String c = String.valueOf(hws.charAt(i)); Matcher m = Pattern.compile("\\h").matcher(prefix + c + suffix); - if (!m.find() || !c.equals(m.group())) - failCount++; + assertTrue(m.find() && c.equals(m.group())); m = Pattern.compile("[\\h]").matcher(prefix + c + suffix); - if (!m.find() || !c.equals(m.group())) - failCount++; + assertTrue(m.find() && c.equals(m.group())); - m = Pattern.compile("\\H").matcher(hws.substring(0, i) + ng + hws.substring(i)); - if (!m.find() || !ng.equals(m.group())) - failCount++; - m = Pattern.compile("[\\H]").matcher(hws.substring(0, i) + ng + hws.substring(i)); - if (!m.find() || !ng.equals(m.group())) - failCount++; + String matcherSubstring = hws.substring(0, i) + ng + hws.substring(i); + + m = Pattern.compile("\\H").matcher(matcherSubstring); + assertTrue(m.find() && ng.equals(m.group())); + m = Pattern.compile("[\\H]").matcher(matcherSubstring); + assertTrue(m.find() && ng.equals(m.group())); } for (int i = 0; i < vws.length(); i++) { String c = String.valueOf(vws.charAt(i)); Matcher m = Pattern.compile("\\v").matcher(prefix + c + suffix); - if (!m.find() || !c.equals(m.group())) - failCount++; + assertTrue(m.find() && c.equals(m.group())); m = Pattern.compile("[\\v]").matcher(prefix + c + suffix); - if (!m.find() || !c.equals(m.group())) - failCount++; + assertTrue(m.find() && c.equals(m.group())); - m = Pattern.compile("\\V").matcher(vws.substring(0, i) + ng + vws.substring(i)); - if (!m.find() || !ng.equals(m.group())) - failCount++; - m = Pattern.compile("[\\V]").matcher(vws.substring(0, i) + ng + vws.substring(i)); - if (!m.find() || !ng.equals(m.group())) - failCount++; + String matcherSubstring = vws.substring(0, i) + ng + vws.substring(i); + m = Pattern.compile("\\V").matcher(matcherSubstring); + assertTrue(m.find() && ng.equals(m.group())); + m = Pattern.compile("[\\V]").matcher(matcherSubstring); + assertTrue(m.find() && ng.equals(m.group())); } // \v in range is interpreted as 0x0B. This is the undocumented behavior - if (!Pattern.compile("[\\v-\\v]").matcher(String.valueOf((char)0x0B)).matches()) - failCount++; - report("horizontalAndVerticalWSTest"); + assertTrue(Pattern.compile("[\\v-\\v]").matcher(String.valueOf((char)0x0B)).matches()); } - private static void linebreakTest() throws Exception { + @Test + public static void linebreakTest() { String linebreaks = new String (new char[] { 0x0A, 0x0B, 0x0C, 0x0D, 0x85, 0x2028, 0x2029 }); String crnl = "\r\n"; - if (!(Pattern.compile("\\R+").matcher(linebreaks).matches() && + assertTrue((Pattern.compile("\\R+").matcher(linebreaks).matches() && Pattern.compile("\\R").matcher(crnl).matches() && Pattern.compile("\\Rabc").matcher(crnl + "abc").matches() && Pattern.compile("\\Rabc").matcher("\rabc").matches() && Pattern.compile("\\R\\R").matcher(crnl).matches() && // backtracking - Pattern.compile("\\R\\n").matcher(crnl).matches()) && // backtracking - !Pattern.compile("((? p = Pattern.compile("[a-z]+").asPredicate(); - if (p.test("")) { - failCount++; - } - if (!p.test("word")) { - failCount++; - } - if (p.test("1234")) { - failCount++; - } - if (!p.test("word1234")) { - failCount++; - } - report("Pattern.asPredicate"); + assertFalse(p.test("")); + assertTrue(p.test("word")); + assertFalse(p.test("1234")); + assertTrue(p.test("word1234")); } // This test is for 8184692 - private static void patternAsMatchPredicate() throws Exception { + @Test + public static void patternAsMatchPredicate() { Predicate p = Pattern.compile("[a-z]+").asMatchPredicate(); - if (p.test("")) { - failCount++; - } - if (!p.test("word")) { - failCount++; - } - if (p.test("1234word")) { - failCount++; - } - if (p.test("1234")) { - failCount++; - } - report("Pattern.asMatchPredicate"); + assertFalse(p.test("")); + assertTrue(p.test("word")); + assertFalse(p.test("1234word")); + assertFalse(p.test("1234")); } // This test is for 8035975 - private static void invalidFlags() throws Exception { + @Test + public static void invalidFlags() { for (int flag = 1; flag != 0; flag <<= 1) { switch (flag) { case Pattern.CASE_INSENSITIVE: @@ -4771,19 +4068,17 @@ // valid flag, continue break; default: - try { - Pattern.compile(".", flag); - failCount++; - } catch (IllegalArgumentException expected) { - } + int finalFlag = flag; + assertThrows(IllegalArgumentException.class, () -> + Pattern.compile(".", finalFlag)); } } - report("Invalid compile flags"); } // This test is for 8158482 - private static void embeddedFlags() throws Exception { - try { + @Test + public static void embeddedFlags() { + //Runs without exception. Pattern.compile("(?i).(?-i)."); Pattern.compile("(?m).(?-m)."); Pattern.compile("(?s).(?-s)."); @@ -4793,13 +4088,10 @@ Pattern.compile("(?x).(?-x)."); Pattern.compile("(?U).(?-U)."); Pattern.compile("(?imsducxU).(?-imsducxU)."); - } catch (PatternSyntaxException x) { - failCount++; - } - report("Embedded flags"); } - private static void grapheme() throws Exception { + @Test + public static void grapheme() throws Exception { final int[] lineNumber = new int[1]; Stream.concat(Files.lines(UCDFiles.GRAPHEME_BREAK_TEST), Files.lines(Paths.get(System.getProperty("test.src", "."), "GraphemeTestCases.txt"))) @@ -4834,15 +4126,12 @@ // System.out.printf(" grapheme:=[%s]%n", g); String group = null; if (!m.find() || !(group = m.group()).equals(g)) { - System.out.println("Failed pattern \\X [" + ln + "] : " + fail("Failed pattern \\X [" + ln + "] : " + "expected: " + g + " - actual: " + group + "(line " + lineNumber[0] + ")"); - failCount++; } } - if (m.find()) { - failCount++; - } + assertFalse(m.find()); // test \b{g} without \X via Pattern Pattern pbg = Pattern.compile("\\b{g}"); m = pbg.matcher(src.toString()); @@ -4851,61 +4140,48 @@ for (String g : graphemes) { String group = null; if (!m.find() || !(group = src.substring(prev, m.end())).equals(g)) { - System.out.println("Failed pattern \\b{g} [" + ln + "] : " + fail("Failed pattern \\b{g} [" + ln + "] : " + "expected: " + g + " - actual: " + group + "(line " + lineNumber[0] + ")"); - failCount++; - } - if (!"".equals(m.group())) { - failCount++; } + assertEquals("", m.group()); prev = m.end(); } - if (m.find()) { - failCount++; - } + assertFalse(m.find()); // (2) test \b{g} + \X via Scanner Scanner s = new Scanner(src.toString()).useDelimiter("\\b{g}"); for (String g : graphemes) { String next = null; if (!s.hasNext(p) || !(next = s.next(p)).equals(g)) { - System.out.println("Failed \\b{g} [" + ln + "] : " + fail("Failed \\b{g} [" + ln + "] : " + "expected: " + g + " - actual: " + next + " (line " + lineNumber[0] + ")"); - failCount++; } } - if (s.hasNext(p)) { - failCount++; - } + assertFalse(s.hasNext(p)); // test \b{g} without \X via Scanner s = new Scanner(src.toString()).useDelimiter("\\b{g}"); for (String g : graphemes) { String next = null; if (!s.hasNext() || !(next = s.next()).equals(g)) { - System.out.println("Failed \\b{g} [" + ln + "] : " + fail("Failed \\b{g} [" + ln + "] : " + "expected: " + g + " - actual: " + next + " (line " + lineNumber[0] + ")"); - failCount++; } } - if (s.hasNext()) { - failCount++; - } + assertFalse(s.hasNext()); }); // some sanity checks - if (!Pattern.compile("\\X{10}").matcher("abcdefghij").matches() || - !Pattern.compile("\\b{g}(?:\\X\\b{g}){5}\\b{g}").matcher("abcde").matches() || - !Pattern.compile("(?:\\X\\b{g}){2}").matcher("\ud800\udc00\ud801\udc02").matches()) - failCount++; + assertTrue(Pattern.compile("\\X{10}").matcher("abcdefghij").matches() && + Pattern.compile("\\b{g}(?:\\X\\b{g}){5}\\b{g}").matcher("abcde").matches() && + Pattern.compile("(?:\\X\\b{g}){2}").matcher("\ud800\udc00\ud801\udc02").matches()); // make sure "\b{n}" still works - if (!Pattern.compile("\\b{1}hello\\b{1} \\b{1}world\\b{1}").matcher("hello world").matches()) - failCount++; - report("Unicode extended grapheme cluster"); + assertTrue(Pattern.compile("\\b{1}hello\\b{1} \\b{1}world\\b{1}").matcher("hello world").matches()); } // hangup/timeout if go into exponential backtracking - private static void expoBacktracking() throws Exception { + @Test + public static void expoBacktracking() { Object[][] patternMatchers = { // 6328855 @@ -4986,28 +4262,21 @@ String p = (String)pm[0]; String s = (String)pm[1]; boolean r = (Boolean)pm[2]; - if (r != Pattern.compile(p).matcher(s).matches()) { - failCount++; - } + assertEquals(r, Pattern.compile(p).matcher(s).matches()); } } - private static void invalidGroupName() { + @Test + public static void invalidGroupName() { // Invalid start of a group name for (String groupName : List.of("", ".", "0", "\u0040", "\u005b", "\u0060", "\u007b", "\u0416")) { for (String pat : List.of("(?<" + groupName + ">)", "\\k<" + groupName + ">")) { - try { - Pattern.compile(pat); - failCount++; - } catch (PatternSyntaxException e) { - if (!e.getMessage().startsWith( + var e = expectThrows(PatternSyntaxException.class, () -> Pattern.compile(pat)); + assertTrue(e.getMessage().startsWith( "capturing group name does not start with a" - + " Latin letter")) { - failCount++; - } - } + + " Latin letter")); } } // Invalid char in a group name @@ -5015,21 +4284,16 @@ "d\u0060", "e\u007b", "f\u0416")) { for (String pat : List.of("(?<" + groupName + ">)", "\\k<" + groupName + ">")) { - try { - Pattern.compile(pat); - failCount++; - } catch (PatternSyntaxException e) { - if (!e.getMessage().startsWith( - "named capturing group is missing trailing '>'")) { - failCount++; - } - } + var e = expectThrows(PatternSyntaxException.class, () -> + Pattern.compile(pat)); + assertTrue(e.getMessage().startsWith( + "named capturing group is missing trailing '>'")); } } - report("Invalid capturing group names"); } - private static void illegalRepetitionRange() { + @Test + public static void illegalRepetitionRange() { // huge integers > (2^31 - 1) String n = BigInteger.valueOf(1L << 32) .toString(); @@ -5039,34 +4303,19 @@ for (String rep : List.of("", "x", ".", ",", "-1", "2,1", n, n + ",", "0," + n, n + "," + m, m, m + ",", "0," + m)) { String pat = ".{" + rep + "}"; - try { - Pattern.compile(pat); - failCount++; - System.out.println("Expected to fail. Pattern: " + pat); - } catch (PatternSyntaxException e) { - if (!e.getMessage().startsWith("Illegal repetition")) { - failCount++; - System.out.println("Unexpected error message: " + e.getMessage()); - } - } catch (Throwable t) { - failCount++; - System.out.println("Unexpected exception: " + t); - } + var e = expectThrows(PatternSyntaxException.class, () -> + Pattern.compile(pat)); + assertTrue(e.getMessage().startsWith("Illegal repetition")); } - report("illegalRepetitionRange"); } - private static void surrogatePairWithCanonEq() { - try { - Pattern.compile("\ud834\udd21", Pattern.CANON_EQ); - } catch (Throwable t) { - failCount++; - System.out.println("Unexpected exception: " + t); - } - report("surrogatePairWithCanonEq"); + @Test + public static void surrogatePairWithCanonEq() { + //Runs without exception + Pattern.compile("\ud834\udd21", Pattern.CANON_EQ); } - private static String s2x(String s) { + public static String s2x(String s) { StringBuilder sb = new StringBuilder(); for (char ch : s.toCharArray()) { sb.append(String.format("\\u%04x", (int)ch)); @@ -5075,7 +4324,8 @@ } // This test is for 8235812, with cases excluded by 8258259 - private static void lineBreakWithQuantifier() { + @Test + public static void lineBreakWithQuantifier() { // key: pattern // value: lengths of input that must match the pattern Map> cases = Map.ofEntries( @@ -5139,20 +4389,17 @@ m.usePattern(p); for (int len : cases.get(patStr)) { for (String in : inputs.get(len)) { - if (!m.reset(in).matches()) { - failCount++; - System.err.println("Expected to match '" + - s2x(in) + "' =~ /" + p + "/"); - } + assertTrue(m.reset(in).matches(), "Expected to match '" + + s2x(in) + "' =~ /" + p + "/"); } } } } - report("lineBreakWithQuantifier"); } // This test is for 8214245 - private static void caseInsensitivePMatch() { + @Test + public static void caseInsensitivePMatch() { for (String input : List.of("abcd", "AbCd", "ABCD")) { for (String pattern : List.of("abcd", "aBcD", "[a-d]{4}", "(?:a|b|c|d){4}", "\\p{Lower}{4}", "\\p{Ll}{4}", @@ -5173,14 +4420,10 @@ "[\\p{gc=Lt}]{4}", "[\\p{general_category=Lt}]{4}", "[\\p{IsTitlecase}]{4}", "[\\p{javaTitleCase}]{4}")) { - if (!Pattern.compile(pattern, Pattern.CASE_INSENSITIVE) + assertTrue(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE) .matcher(input) - .matches()) - { - failCount++; - System.err.println("Expected to match: " + - "'" + input + "' =~ /" + pattern + "/"); - } + .matches(),"Expected to match: " + "'" + input + + "' =~ /" + pattern + "/"); } } @@ -5205,22 +4448,18 @@ "[\\p{gc=Lt}]", "[\\p{general_category=Lt}]", "[\\p{IsTitlecase}]", "[\\p{javaTitleCase}]")) { - if (!Pattern.compile(pattern, Pattern.CASE_INSENSITIVE + assertTrue(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CHARACTER_CLASS) .matcher(input) - .matches()) - { - failCount++; - System.err.println("Expected to match: " + - "'" + input + "' =~ /" + pattern + "/"); - } + .matches(), "Expected to match: " + + "'" + input + "' =~ /" + pattern + "/"); } } - report("caseInsensitivePMatch"); } // This test is for 8237599 - private static void surrogatePairOverlapRegion() { + @Test + public static void surrogatePairOverlapRegion() { String input = "\ud801\udc37"; Pattern p = Pattern.compile(".+"); @@ -5230,15 +4469,16 @@ boolean ok = m.find(); if (!ok || !m.group(0).equals(input.substring(0, 1))) { - failCount++; - System.out.println("Input \"" + input + "\".substr(0, 1)" + - " expected to match pattern \"" + p + "\""); + String errMessage = "Input \"" + input + "\".substr(0, 1)" + + " expected to match pattern \"" + p + "\""; if (ok) { - System.out.println("group(0): \"" + m.group(0) + "\""); + fail(errMessage + System.lineSeparator() + + "group(0): \"" + m.group(0) + "\""); + } else { + fail(errMessage); } } else if (!m.hitEnd()) { - failCount++; - System.out.println("Expected m.hitEnd() == true"); + fail("Expected m.hitEnd() == true"); } p = Pattern.compile(".*(.)"); @@ -5249,19 +4489,22 @@ if (!ok || !m.group(0).equals(input.substring(1, 2)) || !m.group(1).equals(input.substring(1, 2))) { - failCount++; - System.out.println("Input \"" + input + "\".substr(1, 2)" + - " expected to match pattern \"" + p + "\""); + String errMessage = "Input \"" + input + "\".substr(1, 2)" + + " expected to match pattern \"" + p + "\""; if (ok) { - System.out.println("group(0): \"" + m.group(0) + "\""); - System.out.println("group(1): \"" + m.group(1) + "\""); + String msg1 = "group(0): \"" + m.group(0) + "\""; + String msg2 = "group(1): \"" + m.group(1) + "\""; + fail(errMessage + System.lineSeparator() + msg1 + + System.lineSeparator() + msg2); + } else { + fail(errMessage); } } - report("surrogatePairOverlapRegion"); } //This test is for 8037397 - private static void droppedClassesWithIntersection() { + @Test + public static void droppedClassesWithIntersection() { String rx = "[A-Z&&[A-Z]0-9]"; String ry = "[A-Z&&[A-F][G-Z]0-9]"; @@ -5279,15 +4522,20 @@ }); - if (!letterCharsMatch) { - failCount++; - System.out.println("Compiling intersection pattern is dropping a character class in its matcher"); - } + assertTrue(letterCharsMatch, "Compiling intersection pattern is " + + "dropping a character class in its matcher"); - if (!digitCharsDontMatch) { - failCount++; - System.out.println("Compiling intersection pattern is matching digits where it should not"); - } + assertTrue(digitCharsDontMatch, "Compiling intersection pattern is " + + "matching digits where it should not"); + } + //This test is for 8269753 + @Test + public static void errorMessageCaretIndentation() { + String pattern = "\t**"; + var e = expectThrows(PatternSyntaxException.class, () -> + Pattern.compile(pattern)); + var sep = System.lineSeparator(); + assertTrue(e.getMessage().contains(sep + "\t ^")); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java openjdk-17-17.0.4+8/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java --- openjdk-17-17.0.3+7/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8193682 8278794 + * @summary Test Infinite loop while writing on closed Deflater and Inflater. + * @run testng CloseInflaterDeflaterTest + */ +import java.io.*; +import java.util.Random; +import java.util.jar.JarOutputStream; +import java.util.zip.DeflaterInputStream; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPOutputStream; +import java.util.zip.InflaterOutputStream; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.assertThrows; + + +public class CloseInflaterDeflaterTest { + + // Number of bytes to write/read from Deflater/Inflater + private static final int INPUT_LENGTH= 512; + // OutputStream that will throw an exception during a write operation + private static OutputStream outStream = new OutputStream() { + @Override + public void write(byte[] b, int off, int len) throws IOException { + throw new IOException(); + } + @Override + public void write(byte[] b) throws IOException {} + @Override + public void write(int b) throws IOException {} + }; + // InputStream that will throw an exception during a read operation + private static InputStream inStream = new InputStream() { + @Override + public int read(byte[] b, int off, int len) throws IOException { + throw new IOException(); + } + @Override + public int read(byte[] b) throws IOException { throw new IOException();} + @Override + public int read() throws IOException { throw new IOException();} + }; + // Input bytes for read/write operation + private static byte[] inputBytes = new byte[INPUT_LENGTH]; + // Random function to add bytes to inputBytes + private static Random rand = new Random(); + + /** + * DataProvider to specify whether to use close() or finish() of OutputStream + * + * @return Entry object indicating which method to use for closing OutputStream + */ + @DataProvider + public Object[][] testOutputStreams() { + return new Object[][] { + { true }, + { false }, + }; + } + + /** + * DataProvider to specify on which outputstream closeEntry() has to be called + * + * @return Entry object returning either JarOutputStream or ZipOutputStream + */ + @DataProvider + public Object[][] testZipAndJar() throws IOException{ + return new Object[][] { + { new JarOutputStream(outStream)}, + { new ZipOutputStream(outStream)}, + }; + } + + /** + * Add inputBytes array with random bytes to write into OutputStream + */ + @BeforeTest + public void before_test() + { + rand.nextBytes(inputBytes); + } + + /** + * Test for infinite loop by writing bytes to closed GZIPOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testGZip(boolean useCloseMethod) throws IOException { + GZIPOutputStream gzip = new GZIPOutputStream(outStream); + gzip.write(inputBytes, 0, INPUT_LENGTH); + assertThrows(IOException.class, () -> { + // Close GZIPOutputStream + if (useCloseMethod) { + gzip.close(); + } else { + gzip.finish(); + } + }); + // Write on a closed GZIPOutputStream, closed Deflater IOException expected + assertThrows(NullPointerException.class , () -> gzip.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed DeflaterOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testDeflaterOutputStream(boolean useCloseMethod) throws IOException { + DeflaterOutputStream def = new DeflaterOutputStream(outStream); + assertThrows(IOException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH)); + assertThrows(IOException.class, () -> { + // Close DeflaterOutputStream + if (useCloseMethod) { + def.close(); + } else { + def.finish(); + } + }); + // Write on a closed DeflaterOutputStream, 'Deflater has been closed' NPE is expected + assertThrows(NullPointerException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by reading bytes from closed DeflaterInputStream + * + * @throws IOException if an error occurs + */ + @Test + public void testDeflaterInputStream() throws IOException { + DeflaterInputStream def = new DeflaterInputStream(inStream); + assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH)); + // Close DeflaterInputStream + def.close(); + // Read from a closed DeflaterInputStream, closed Deflater IOException expected + assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed InflaterOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testInflaterOutputStream(boolean useCloseMethod) throws IOException { + InflaterOutputStream inf = new InflaterOutputStream(outStream); + assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH)); + assertThrows(IOException.class , () -> { + // Close InflaterOutputStream + if (useCloseMethod) { + inf.close(); + } else { + inf.finish(); + } + }); + // Write on a closed InflaterOutputStream , closed Inflater IOException expected + assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed ZipOutputStream/JarOutputStream + * + * @param zip will be the instance of either JarOutputStream or ZipOutputStream + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testZipAndJar") + public void testZipCloseEntry(ZipOutputStream zip) throws IOException { + assertThrows(IOException.class , () -> zip.putNextEntry(new ZipEntry(""))); + zip.write(inputBytes, 0, INPUT_LENGTH); + assertThrows(IOException.class , () -> zip.closeEntry()); + // Write on a closed ZipOutputStream , 'Deflater has been closed' NPE is expected + assertThrows(NullPointerException.class , () -> zip.write(inputBytes, 0, INPUT_LENGTH)); + } + +} diff -Nru openjdk-17-17.0.3+7/test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java openjdk-17-17.0.4+8/test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java --- openjdk-17-17.0.3+7/test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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.ByteArrayOutputStream; +import java.util.function.Consumer; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertThrows; + +/** + * @test + * @bug 8277087 + * @summary Verifies various use cases when the zip comment should be empty + * @run testng EmptyComment + */ +public final class EmptyComment { + + @DataProvider() + Object[][] longLengths() { + return new Object[][]{{0xFFFF + 1}, {0xFFFF + 2}, {0xFFFF * 2}}; + } + + /** + * Overflow, the text is too long to be stored as a comment. + */ + @Test(dataProvider = "longLengths") + void testOverflow(int length) throws Exception { + test(zos -> assertThrows(IllegalArgumentException.class, () -> { + zos.setComment("X".repeat(length)); + })); + } + + /** + * Simple cases where the comment is set to the empty text. + */ + @Test + void testSimpleCases() throws Exception { + test(zos -> {/* do nothing */}); + test(zos -> zos.setComment(null)); + test(zos -> zos.setComment("")); + test(zos -> { + zos.setComment(""); + zos.setComment(null); + }); + test(zos -> { + zos.setComment(null); + zos.setComment(""); + }); + test(zos -> { + zos.setComment("Comment"); + zos.setComment(null); + }); + test(zos -> { + zos.setComment("Comment"); + zos.setComment(""); + }); + } + + private static void test(Consumer test) throws Exception { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(baos)) { + + test.accept(zos); + + zos.putNextEntry(new ZipEntry("x")); + zos.finish(); + + byte[] data = baos.toByteArray(); + + if (data.length > 0xFFFF) { // just in case + throw new RuntimeException("data is too big: " + data.length); + } + int pk = data.length - ZipFile.ENDHDR; + if (data[pk] != 'P' || data[pk + 1] != 'K') { + throw new RuntimeException("PK is not found"); + } + // Since the comment is empty this will be two last bytes + int pos = data.length - ZipFile.ENDHDR + ZipFile.ENDCOM; + + int len = (data[pos] & 0xFF) + ((data[pos + 1] & 0xFF) << 8); + if (len != 0) { + throw new RuntimeException("zip comment is not empty: " + len); + } + } + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java openjdk-17-17.0.4+8/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java --- openjdk-17-17.0.3+7/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8277922 + @key headful + @summary TableCellRenderer of JTable cell with Boolean data should not + support any AccessibleAction. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleTable; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; + +public class BooleanRendererHasAccessibleActionTest { + private volatile JFrame frame; + private volatile JTable table; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + final BooleanRendererHasAccessibleActionTest test = + new BooleanRendererHasAccessibleActionTest(); + + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.createGUI(); + } + }); + Robot robot = new Robot(); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.runTest(); + } + }); + } finally { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.dispose(); + } + }); + } + } + + private void createGUI() { + frame = new JFrame("BooleanRendererHasAccessibleActionTest"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + Container content = frame.getContentPane(); + content.setLayout(new BorderLayout()); + + String[] tblColNames = {"Column 1", "Column 2", "Column 3"}; + Object[][] tblData = { + {Boolean.TRUE, "Text 1", Boolean.FALSE}, + {Boolean.FALSE, "Text 2", Boolean.TRUE} + }; + final DefaultTableModel tblModel = new DefaultTableModel( + tblData, tblColNames) { + @Override + public Class getColumnClass(int column) { + return getValueAt(0, column).getClass(); + } + }; + table = new JTable(tblModel); + table.setPreferredScrollableViewportSize(new Dimension(400, 100)); + + JScrollPane tblScroller = new JScrollPane(table); + tblScroller.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + tblScroller.setVerticalScrollBarPolicy( + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS + ); + content.add(tblScroller, BorderLayout.CENTER); + + frame.pack(); + frame.setVisible(true); + } + + private void dispose() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + private void runTest() { + if (table == null) { + throw new RuntimeException("'table' should not be null"); + } + + testAccessibleActionInCellRenderer(0, 0, true); + testAccessibleActionInCellRenderer(1, 0, true); + testAccessibleActionInCellRenderer(0, 2, true); + testAccessibleActionInCellRenderer(1, 2, true); + + testAccessibleActionInCell(0, 0, true); + testAccessibleActionInCell(1, 0, true); + testAccessibleActionInCell(0, 2, true); + testAccessibleActionInCell(1, 2, true); + + System.out.println("Test passed."); + } + + private void testAccessibleActionInCellRenderer(int row, int column, + boolean shouldBeNull) { + System.out.println(String.format( + "testAccessibleActionInCellRenderer():" + + " row='%d', column='%d', shouldBeNull='%b'", + row, column, shouldBeNull)); + + TableCellRenderer cellRenderer = table.getCellRenderer(row, column); + if (!(cellRenderer instanceof Accessible)) { + throw new RuntimeException("'cellRenderer' is not Accessible"); + } + + AccessibleContext cellRendererAc = + ((Accessible) cellRenderer).getAccessibleContext(); + if (cellRendererAc == null) { + throw new RuntimeException("'cellRendererAc' should not be null"); + } + + AccessibleAction cellRendererAa = cellRendererAc.getAccessibleAction(); + if ((shouldBeNull && (cellRendererAa != null)) || + (!shouldBeNull && (cellRendererAa == null))) { + throw new RuntimeException( + "Test failed. 'cellRendererAa' is not as should be"); + } + } + + private void testAccessibleActionInCell(int row, int column, + boolean shouldBeNull) { + System.out.println(String.format("testAccessibleActionInCell():" + + " row='%d', column='%d', shouldBeNull='%b'", + row, column, shouldBeNull)); + + AccessibleContext tblAc = table.getAccessibleContext(); + AccessibleTable accessibleTbl = tblAc.getAccessibleTable(); + if (accessibleTbl == null) { + throw new RuntimeException("'accessibleTbl' should not be null"); + } + + Accessible cellAccessible = accessibleTbl.getAccessibleAt(row, column); + AccessibleContext cellAc = cellAccessible.getAccessibleContext(); + if (cellAc == null) { + throw new RuntimeException("'cellAc' should not be null"); + } + + AccessibleAction cellAa = cellAc.getAccessibleAction(); + if ((shouldBeNull && (cellAa != null)) || + (!shouldBeNull && (cellAa == null))) { + throw new RuntimeException( + "Test failed. 'cellAa' is not as should be"); + } + } +} Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/black_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/black_cmyk.jpg differ Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/blue_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/blue_cmyk.jpg differ diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/CMYKJPEGTest.java openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/CMYKJPEGTest.java --- openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/CMYKJPEGTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/CMYKJPEGTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + * + * This test verifies that using the built-in ImageI/O JPEG plugin that JPEG images + * that are in a CMYK ColorSpace can be read into a BufferedImage using the convemience + * APIS and that and the colours are properly interpreted. + * Since there is no standard JDK CMYK ColorSpace, this requires that either the image + * contain an ICC_Profile which can be used by the plugin to create an ICC_ColorSpace + * or that the plugin provides a suitable default CMYK ColorSpace instance by some other means. + * + * The test further verifies that the resultant BufferedImage will be re-written as a CMYK + * BufferedImage. It can do this so long as the BufferedImage has that CMYK ColorSpace + * used by its ColorModel. + * + * The verification requires re-reading again the re-written image and checking the + * re-read image still has a CMYK ColorSpace and the same colours. + * + * Optionally - not for use in the test harness - the test can be passed a parameter + * -display to create a UI which renders all the images the test is + * verifying so it can be manually verified + */ + +/* + * @test + * @bug 8274735 + * @summary Verify CMYK JPEGs can be read and written + */ + +import java.awt.Color; +import static java.awt.Color.*; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +public class CMYKJPEGTest { + + static String[] fileNames = { + "black_cmyk.jpg", + "white_cmyk.jpg", + "gray_cmyk.jpg", + "red_cmyk.jpg", + "blue_cmyk.jpg", + "green_cmyk.jpg", + "cyan_cmyk.jpg", + "magenta_cmyk.jpg", + "yellow_cmyk.jpg", + }; + + static Color[] colors = { + black, + white, + gray, + red, + blue, + green, + cyan, + magenta, + yellow, + }; + + static boolean display; + + static BufferedImage[] readImages; + static BufferedImage[] writtenImages; + static int imageIndex = 0; + + public static void main(String[] args) throws Exception { + + if (args.length > 0) { + display = "-display".equals(args[0]); + } + + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String prefix = dir+sep; + + readImages = new BufferedImage[fileNames.length]; + writtenImages = new BufferedImage[fileNames.length]; + + for (String fileName : fileNames) { + String color = fileName.replace("_cmyk.jpg", ""); + test(prefix+fileName, color, imageIndex++); + } + if (display) { + SwingUtilities.invokeAndWait(() -> createUI()); + } + } + + static void test(String fileName, String color, int index) + throws IOException { + + readImages[index] = ImageIO.read(new File(fileName)); + verify(readImages[index], color, colors[index]); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(readImages[index], "jpg", baos); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + writtenImages[index] = ImageIO.read(bais); + verify(writtenImages[index], color, colors[index]); + } + + static void verify(BufferedImage img, String colorName, Color c) { + ColorModel cm = img.getColorModel(); + int tc = cm.getNumComponents(); + int cc = cm.getNumColorComponents(); + if (cc != 4 || tc != 4) { + throw new RuntimeException("Unexpected num comp for " + img); + } + + int rgb = img.getRGB(0,0); + int c_red = c.getRed(); + int c_green = c.getGreen(); + int c_blue = c.getBlue(); + int i_red = (rgb & 0x0ff0000) >> 16; + int i_green = (rgb & 0x000ff00) >> 8; + int i_blue = (rgb & 0x00000ff); + int tol = 16; + if ((Math.abs(i_red - c_red) > tol) || + (Math.abs(i_green - c_green) > tol) || + (Math.abs(i_blue - c_blue) > tol)) + { + System.err.println("red="+i_red+" green="+i_green+" blue="+i_blue); + throw new RuntimeException("Too different " + img + " " + colorName + " " + c); + } + } + + static class ImageComp extends JComponent { + + BufferedImage img; + + ImageComp(BufferedImage img) { + this.img = img; + } + + public Dimension getPreferredSize() { + return new Dimension(img.getWidth(), img.getHeight()); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public void paintComponent(Graphics g) { + super.paintComponent(g); + g.drawImage(img, 0, 0, null); + } + } + + static void createUI() { + JFrame f = new JFrame("CMYK JPEG Test"); + JPanel p = new JPanel(); + p.setLayout(new GridLayout(3, colors.length, 10, 10)); + for (String s : fileNames) { + p.add(new JLabel(s.replace("_cmyk.jpg", ""))); + } + for (BufferedImage i : readImages) { + p.add(new ImageComp(i)); + } + for (BufferedImage i : writtenImages) { + p.add(new ImageComp(i)); + } + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + f.add(p); + f.pack(); + f.setVisible(true); + } +} Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/cyan_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/cyan_cmyk.jpg differ Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/gray_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/gray_cmyk.jpg differ Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/green_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/green_cmyk.jpg differ Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/magenta_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/magenta_cmyk.jpg differ Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/red_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/red_cmyk.jpg differ Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/white_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/white_cmyk.jpg differ Binary files /tmp/tmp8qxqkmbv/qSbix7OOg0/openjdk-17-17.0.3+7/test/jdk/javax/imageio/plugins/jpeg/CMYK/yellow_cmyk.jpg and /tmp/tmp8qxqkmbv/PPFozQCdsE/openjdk-17-17.0.4+8/test/jdk/javax/imageio/plugins/jpeg/CMYK/yellow_cmyk.jpg differ diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java openjdk-17-17.0.4+8/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java --- openjdk-17-17.0.3+7/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * 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,6 +43,7 @@ import java.rmi.registry.Registry; import java.util.ArrayList; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -110,17 +111,21 @@ try { AtomicBoolean error = new AtomicBoolean(false); AtomicBoolean bindError = new AtomicBoolean(false); + // The predicate below tries to recognise failures. On a port clash, it sees e.g. + // Error: Exception thrown by the agent : java.rmi.server.ExportException: Port already in use: 46481; nested exception is: + // ...and will never see "main enter" from TestApp. p = ProcessTools.startProcess( TEST_APP_NAME + "{" + name + "}", pb, (line) -> { - if (line.toLowerCase().contains("exception") - || line.toLowerCase().contains("error")) { + if (line.contains("Exception")) { error.set(true); + bindError.set(line.toLowerCase().contains("port already in use")); + return true; // On Exception, app will never start } - bindError.set(line.toLowerCase().contains("bindexception")); - return true; - }); + return line.contains("main enter"); + }, + 60, TimeUnit.SECONDS); if (bindError.get()) { throw new BindException("Process could not be started"); } else if (error.get()) { @@ -164,9 +169,25 @@ } private static final String TEST_APP_NAME = "TestApp"; + private static final int FREE_PORT_ATTEMPTS = 10; private static void testDefaultAgent(String propertyFile) throws Exception { - int port = Utils.getFreePort(); + for (int i = 1; i <= FREE_PORT_ATTEMPTS; i++) { + int port = Utils.getFreePort(); + System.out.println("Attempting testDefaultAgent(" + propertyFile + ") with port: " + port); + try { + testDefaultAgent(propertyFile, port); + break; // return succesfully + } catch (BindException b) { + // Retry with new port. Throw if last iteration: + if (i == FREE_PORT_ATTEMPTS) { + throw(b); + } + } + } + } + + private static void testDefaultAgent(String propertyFile, int port) throws Exception { String propFile = System.getProperty("test.src") + File.separator + propertyFile; List pbArgs = new ArrayList<>(Arrays.asList( "-cp", @@ -235,53 +256,32 @@ public static void main(String[] args) throws Exception { System.out.println("---" + DefaultAgentFilterTest.class.getName() + "-main: starting ..."); - boolean retry = false; - do { - try { - // filter DefaultAgentFilterTest$MyTestObject - testDefaultAgent("mgmt1.properties"); - System.out.println("----\tTest FAILED !!"); - throw new RuntimeException("---" + DefaultAgentFilterTest.class.getName() + " - No exception reported"); - } catch (Exception ex) { - if (ex instanceof InvocationTargetException) { - if (ex.getCause() instanceof BindException - || ex.getCause() instanceof java.rmi.ConnectException) { - System.out.println("Failed to allocate ports. Retrying ..."); - retry = true; - } - } else if (ex instanceof InvalidClassException) { - System.out.println("----\tTest PASSED !!"); - } else if (ex instanceof UnmarshalException - && ((UnmarshalException) ex).getCause() instanceof InvalidClassException) { - System.out.println("----\tTest PASSED !!"); - } else { - System.out.println(ex); - System.out.println("----\tTest FAILED !!"); - throw ex; - } - } - } while (retry); - retry = false; - do { - try { - // filter non-existent class - testDefaultAgent("mgmt2.properties"); + try { + // filter DefaultAgentFilterTest$MyTestObject + testDefaultAgent("mgmt1.properties"); + System.out.println("----\tTest FAILED !!"); + throw new RuntimeException("---" + DefaultAgentFilterTest.class.getName() + " - No exception reported"); + } catch (Exception ex) { + if (ex instanceof InvalidClassException) { System.out.println("----\tTest PASSED !!"); - } catch (Exception ex) { - if (ex instanceof InvocationTargetException) { - if (ex.getCause() instanceof BindException - || ex.getCause() instanceof java.rmi.ConnectException) { - System.out.println("Failed to allocate ports. Retrying ..."); - retry = true; - } - } else { - System.out.println(ex); - System.out.println("----\tTest FAILED !!"); - throw ex; - } + } else if (ex instanceof UnmarshalException + && ((UnmarshalException) ex).getCause() instanceof InvalidClassException) { + System.out.println("----\tTest PASSED !!"); + } else { + System.out.println(ex); + System.out.println("----\tTest FAILED !!"); + throw ex; } - } while (retry); - + } + try { + // filter non-existent class + testDefaultAgent("mgmt2.properties"); + System.out.println("----\tTest PASSED !!"); + } catch (Exception ex) { + System.out.println(ex); + System.out.println("----\tTest FAILED !!"); + throw ex; + } System.out.println("---" + DefaultAgentFilterTest.class.getName() + "-main: finished ..."); } diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/net/ssl/compatibility/JdkInfo.java openjdk-17-17.0.4+8/test/jdk/javax/net/ssl/compatibility/JdkInfo.java --- openjdk-17-17.0.3+7/test/jdk/javax/net/ssl/compatibility/JdkInfo.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/net/ssl/compatibility/JdkInfo.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 +22,9 @@ */ import java.nio.file.Path; +import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; /* @@ -37,10 +39,10 @@ public final Path javaPath; public final String version; - public final String supportedProtocols; - public final String enabledProtocols; - public final String supportedCipherSuites; - public final String enabledCipherSuites; + public final List supportedProtocols; + public final List enabledProtocols; + public final List supportedCipherSuites; + public final List enabledCipherSuites; public final boolean supportsSNI; public final boolean supportsALPN; @@ -54,13 +56,26 @@ } String[] attributes = Utilities.split(output, Utilities.PARAM_DELIMITER); - version = attributes[0].replaceAll(".*=", ""); - supportedProtocols = attributes[1].replaceAll(".*=", ""); - enabledProtocols = attributes[2].replaceAll(".*=", ""); - supportedCipherSuites = attributes[3].replaceAll(".*=", ""); - enabledCipherSuites = attributes[4].replaceAll(".*=", ""); - supportsSNI = Boolean.valueOf(attributes[5].replaceAll(".*=", "")); - supportsALPN = Boolean.valueOf(attributes[6].replaceAll(".*=", "")); + version = parseAttribute(attributes[0]); + supportedProtocols = parseListAttribute(attributes[1]); + enabledProtocols = parseListAttribute(attributes[2]); + supportedCipherSuites = parseListAttribute(attributes[3]); + enabledCipherSuites = parseListAttribute(attributes[4]); + supportsSNI = parseBooleanAttribute(attributes[5]); + supportsALPN = parseBooleanAttribute(attributes[6]); + } + + private List parseListAttribute(String attribute) { + attribute = parseAttribute(attribute); + return Arrays.asList(attribute.split(",")); + } + + private boolean parseBooleanAttribute(String attribute) { + attribute = parseAttribute(attribute); + return Boolean.parseBoolean(attribute); + } + private String parseAttribute(String attribute) { + return attribute.replaceAll(".*=", ""); } // Determines the specific attributes for the specified JDK. diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java openjdk-17-17.0.4+8/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java --- openjdk-17-17.0.3+7/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * 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,23 +21,21 @@ * questions. */ -/** +/* * @test * @bug 8182577 - * @summary Verifies if moving focus via custom ButtonModel causes crash + * @summary Verifies if moving focus to JToggleButton with DefaultButtonModel + * that is added to a ButtonGroup doesn't throw ClassCastException * @key headful * @run main DefaultButtonModelCrashTest */ import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Point; import java.awt.Robot; import java.awt.event.KeyEvent; import javax.swing.ButtonModel; import javax.swing.DefaultButtonModel; import javax.swing.JCheckBox; -import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTextField; @@ -45,8 +43,6 @@ public class DefaultButtonModelCrashTest { private JFrame frame = null; - private JPanel panel; - private volatile Point p = null; public static void main(String[] args) throws Exception { new DefaultButtonModelCrashTest(); @@ -58,29 +54,34 @@ robot.setAutoDelay(200); SwingUtilities.invokeAndWait(() -> go()); robot.waitForIdle(); + robot.delay(1000); robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); robot.delay(100); robot.keyPress(KeyEvent.VK_TAB); robot.keyRelease(KeyEvent.VK_TAB); } finally { - if (frame != null) { SwingUtilities.invokeAndWait(()->frame.dispose()); } + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } } private void go() { - frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - Container contentPane = frame.getContentPane(); - ButtonModel model = new DefaultButtonModel(); + ButtonModel model = new DefaultButtonModel(); JCheckBox check = new JCheckBox("a bit broken"); check.setModel(model); - panel = new JPanel(new BorderLayout()); + + JPanel panel = new JPanel(new BorderLayout()); panel.add(new JTextField("Press Tab (twice?)"), BorderLayout.NORTH); panel.add(check); - contentPane.add(panel); + + frame.getContentPane().add(panel); frame.setLocationRelativeTo(null); frame.pack(); frame.setVisible(true); diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java openjdk-17-17.0.4+8/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java --- openjdk-17-17.0.3+7/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/swing/JCheckBox/ImageCheckboxFocus/ImageCheckboxTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ /* * @test * @key headful - * @bug 8216358 + * @bug 8216358 8279586 * @summary [macos] The focus is invisible when tab to "Image Radio Buttons" and "Image CheckBoxes" * @library ../../regtesthelpers/ * @build Util @@ -51,8 +51,12 @@ BufferedImage.TYPE_INT_ARGB); BufferedImage imageFocus = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB); + BufferedImage imageFocusNotPainted = new BufferedImage(100, 50, + BufferedImage.TYPE_INT_ARGB); + CustomCheckBox checkbox = new CustomCheckBox("Test", new MyIcon(Color.GREEN)); + checkbox.setFocusPainted(true); checkbox.setSize(100, 50); checkbox.setFocused(false); checkbox.paint(imageNoFocus.createGraphics()); @@ -64,6 +68,17 @@ ImageIO.write(imageNoFocus, "png", new File("imageNoFocus.png")); throw new Exception("Changing focus is not visualized"); } + + checkbox.setFocusPainted(false); + checkbox.paint(imageFocusNotPainted.createGraphics()); + + if (!Util.compareBufferedImages(imageFocusNotPainted, imageNoFocus)) { + ImageIO.write(imageFocusNotPainted, "png", + new File("imageFocusNotPainted.png")); + ImageIO.write(imageFocus, "png", new File("imageFocus.png")); + ImageIO.write(imageNoFocus, "png", new File("imageNoFocus.png")); + throw new Exception("setFocusPainted(false) is ignored"); + } } class MyIcon implements Icon { diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/swing/plaf/aqua/JInternalFrameBorderTest.java openjdk-17-17.0.4+8/test/jdk/javax/swing/plaf/aqua/JInternalFrameBorderTest.java --- openjdk-17-17.0.3+7/test/jdk/javax/swing/plaf/aqua/JInternalFrameBorderTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/swing/plaf/aqua/JInternalFrameBorderTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 + * @key headful + * @bug 8139173 + * @requires (os.family == "mac") + * @summary Verify JInternalFrame's border + * @run main JInternalFrameBorderTest + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class JInternalFrameBorderTest { + + private static JFrame frame; + private static JDesktopPane desktopPane; + private static JInternalFrame internalFrame; + private static final int LIMIT = 100; + private static Robot robot; + private static Point pos; + private static Rectangle rect; + private static Insets insets; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + createUI(); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + pos = internalFrame.getLocationOnScreen(); + rect = internalFrame.getBounds(); + insets = internalFrame.getInsets(); + }); + robot.waitForIdle(); + + // bottom + int x = pos.x + rect.x + rect.width/2; + int y = pos.y + rect.y + rect.height - insets.bottom + 1; + Color colorBottom = robot.getPixelColor(x, y); + + // left + x = pos.x + rect.x + insets.left - 1; + y = pos.y + rect.y + rect.height/2; + Color colorLeft = robot.getPixelColor(x, y); + + // right + x = pos.x + rect.x + rect.width - insets.left + 1; + y = pos.y + rect.y + rect.height/2; + Color colorRight = robot.getPixelColor(x, y); + + robot.waitForIdle(); + cleanUp(); + + int diff = getDiff(colorLeft, colorBottom); + if (diff > LIMIT) { + throw new RuntimeException("Unexpected border bottom=" + + colorBottom + " left=" + colorLeft); + } + diff = getDiff(colorRight, colorBottom); + if (diff > LIMIT) { + throw new RuntimeException("Unexpected border bottom=" + + colorBottom + " right=" + colorRight); + } + } + + private static void createUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + try { + UIManager.setLookAndFeel("com.apple.laf.AquaLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("Cannot initialize Aqua L&F"); + } + desktopPane = new JDesktopPane() { + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + g.setColor(Color.BLUE); + g.fillRect(0, 0, getWidth(), getHeight()); + } + }; + internalFrame = new JInternalFrame(); + frame = new JFrame(); + internalFrame.setSize(500, 200); + internalFrame.setVisible(true); + desktopPane.add(internalFrame); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(desktopPane, "Center"); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + }); + } + + private static int getDiff(Color c1, Color c2) { + int r = Math.abs(c1.getRed() - c2.getRed()); + int g = Math.abs(c1.getGreen() - c2.getGreen()); + int b = Math.abs(c1.getBlue() - c2.getBlue()); + return r + g + b; + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(() -> { + frame.dispose(); + }); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java openjdk-17-17.0.4+8/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java --- openjdk-17-17.0.3+7/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * 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,50 +24,52 @@ import java.io.File; import java.io.FileReader; +import java.util.concurrent.CountDownLatch; + import javax.swing.SwingUtilities; import javax.swing.text.Document; import javax.swing.text.html.HTMLEditorKit; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + /* @test @bug 8078268 @summary javax.swing.text.html.parser.Parser parseScript incorrectly optimized - @author Mikhail Cherkasov @run main bug8078268 */ public class bug8078268 { - static volatile boolean parsingDone = false; - static volatile Exception exception; + private static final long TIMEOUT = 10_000; + + private static final String FILENAME = "slowparse.html"; + + private static final CountDownLatch latch = new CountDownLatch(1); + private static volatile Exception exception; public static void main(String[] args) throws Exception { - long timeout = 10_000; - long s = System.currentTimeMillis(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { HTMLEditorKit htmlKit = new HTMLEditorKit(); Document doc = htmlKit.createDefaultDocument(); try { - htmlKit.read(new FileReader(getDirURL() + "slowparse.html"), doc, 0); - parsingDone = true; + htmlKit.read(new FileReader(getAbsolutePath()), doc, 0); } catch (Exception e) { exception = e; } + latch.countDown(); } }); - while (!parsingDone && exception == null && System.currentTimeMillis() - s < timeout) { - Thread.sleep(200); + + if (!latch.await(TIMEOUT, MILLISECONDS)) { + throw new RuntimeException("Parsing takes too long."); } - final long took = System.currentTimeMillis() - s; if (exception != null) { throw exception; } - if (took > timeout) { - throw new RuntimeException("Parsing takes too long."); - } } - static String getDirURL() { - return new File(System.getProperty("test.src", ".")).getAbsolutePath() + - File.separator; + private static String getAbsolutePath() { + return System.getProperty("test.src", ".") + + File.separator + FILENAME; } } diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/xml/crypto/dsig/BadXPointer.java openjdk-17-17.0.4+8/test/jdk/javax/xml/crypto/dsig/BadXPointer.java --- openjdk-17-17.0.3+7/test/jdk/javax/xml/crypto/dsig/BadXPointer.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/xml/crypto/dsig/BadXPointer.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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.Asserts; +import jdk.test.lib.Utils; +import jdk.test.lib.security.XMLUtils; + +import javax.xml.crypto.URIReferenceException; +import javax.xml.crypto.dsig.XMLSignatureException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.spec.ECGenParameterSpec; + +/** + * @test + * @bug 8278186 + * @summary reject malformed xpointer(id('a')) gracefully + * @library /test/lib + * @modules java.xml.crypto + */ +public class BadXPointer { + + public static void main(String[] args) throws Exception { + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); + kpg.initialize(new ECGenParameterSpec("secp256r1")); + KeyPair kp = kpg.generateKeyPair(); + + var signer = XMLUtils.signer(kp.getPrivate(), kp.getPublic()); + var doc = XMLUtils.string2doc(""); + + // No enclosing ' for id + Utils.runAndCheckException( + () -> signer.signEnveloping(doc, "a", "#xpointer(id('a))"), + ex -> Asserts.assertTrue(ex instanceof XMLSignatureException + && ex.getCause() instanceof URIReferenceException + && ex.getMessage().contains("Could not find a resolver"), + ex.toString())); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/javax/xml/jaxp/XPath/InvalidXPath.java openjdk-17-17.0.4+8/test/jdk/javax/xml/jaxp/XPath/InvalidXPath.java --- openjdk-17-17.0.3+7/test/jdk/javax/xml/jaxp/XPath/InvalidXPath.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/javax/xml/jaxp/XPath/InvalidXPath.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2022, 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 - * 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 8284548 - * @summary Test whether the expected exception is thrown when - * trying to compile an invalid XPath expression. - * @run main InvalidXPath - */ - -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -public class InvalidXPath { - - public static void main(String... args) { - // define an invalid XPath expression - final String invalidXPath = ">>"; - - // expect XPathExpressionException when the invalid XPath expression is compiled - try { - XPathFactory.newInstance().newXPath().compile(invalidXPath); - } catch (XPathExpressionException e) { - System.out.println("Caught expected exception: " + e.getClass().getName() + - "(" + e.getMessage() + ")."); - } catch (Exception e) { - System.out.println("Caught unexpected exception: " + e.getClass().getName() + - "(" + e.getMessage() + ")!"); - throw e; - } - } -} diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/build-tests.sh openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/build-tests.sh --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/build-tests.sh 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/build-tests.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. -# 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. -# - -. config.sh - -Log false "Building Vector API tests, $(date)\n" - -# For each type -for type in byte short int long float double -do - Type="$(tr '[:lower:]' '[:upper:]' <<< ${type:0:1})${type:1}" - - # For each size - for bits in 64 128 256 512 - do - vectorteststype=${typeprefix}${Type}${bits}VectorTests - # Compile - Log true "Compiling ${vectorteststype}... " - Log false "\n${JAVAC} -cp \"${VECTORTESTS_HOME_CP}$SEPARATOR${TESTNG_JAR}\" --add-modules=jdk.incubator.vector $vectorteststype.java 2>&1" - compilation=$(${JAVAC} -cp "${VECTORTESTS_HOME_CP}$SEPARATOR${TESTNG_JAR}" \ - --add-modules=jdk.incubator.vector $vectorteststype.java 2>&1) - if [[ $compilation == *"error"* ]]; then - Log true "$compilation\n" - exit -1 - else - Log false "$compilation\n" - fi - Log true "done\n" - done -done - -rm -fr build - - diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Byte128VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Byte128VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Byte128VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Byte128VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3264,13 +3264,16 @@ byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Byte256VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Byte256VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Byte256VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Byte256VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3264,13 +3264,16 @@ byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Byte512VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Byte512VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Byte512VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Byte512VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3264,13 +3264,16 @@ byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Byte64VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Byte64VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Byte64VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Byte64VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3264,13 +3264,16 @@ byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -231,10 +231,10 @@ } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index) { - int i = 0; + static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3269,13 +3269,16 @@ byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane(0, (byte)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (byte)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(byte a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/clean.sh openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/clean.sh --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/clean.sh 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/clean.sh 2022-07-14 08:05:38.000000000 +0000 @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. # 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,4 +24,4 @@ # questions. # -rm -rf *.class build.log test-output +rm -rf build.log diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/config.sh openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/config.sh --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/config.sh 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/config.sh 2022-07-14 08:05:38.000000000 +0000 @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. # 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,9 +35,6 @@ SEPARATOR=":" TYPEPREFIX="" TEMPLATE_FILE="unit_tests.template" -TESTNG_JAR="${TESTNG_PLUGIN}/plugins/org.testng.source_6.13.1.r201712040515.jar" -TESTNG_RUN_JAR="${TESTNG_PLUGIN}/plugins/org.testng_6.13.1.r201712040515.jar" -JCOMMANDER_JAR="${TESTNG_PLUGIN}/plugins/com.beust.jcommander_1.72.0.jar" TEST_ITER_COUNT=100 PERF_TEMPLATE_FILE="perf_tests.template" diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Double128VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Double128VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Double128VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Double128VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2449,13 +2449,16 @@ double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Double256VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Double256VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Double256VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Double256VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2449,13 +2449,16 @@ double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Double512VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Double512VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Double512VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Double512VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2449,13 +2449,16 @@ double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Double64VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Double64VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Double64VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Double64VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2449,13 +2449,16 @@ double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -231,10 +231,10 @@ } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index) { - int i = 0; + static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2454,13 +2454,16 @@ double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane(0, (double)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (double)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(double a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Float128VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Float128VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Float128VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Float128VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2459,13 +2459,16 @@ float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Float256VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Float256VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Float256VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Float256VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2459,13 +2459,16 @@ float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Float512VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Float512VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Float512VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Float512VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2459,13 +2459,16 @@ float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Float64VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Float64VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Float64VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Float64VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2459,13 +2459,16 @@ float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -231,10 +231,10 @@ } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index) { - int i = 0; + static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -2464,13 +2464,16 @@ float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane(0, (float)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (float)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(float a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/gen-tests.sh openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/gen-tests.sh --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/gen-tests.sh 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/gen-tests.sh 2022-07-14 08:05:38.000000000 +0000 @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. # 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,20 +28,10 @@ # You can regenerate the source files, # and you can clean them up. # FIXME: Move this script under $REPO/make/gensrc/ -list_mech_gen() { - ( # List MG files physically present - grep -il 'mechanically generated.*do not edit' $(find * -name \*.java -print) - # List MG files currently deleted (via --clean) - hg status -nd . - ) | egrep '(^|/)(Byte|Short|Int|Long|Float|Double)(Scalar|([0-9Max]+Vector)).*\.java$' -} case $* in '') CLASS_FILTER='*';; --generate*) CLASS_FILTER=${2-'*'};; ---clean) MG=$(list_mech_gen); set -x; rm -f $MG; exit;; ---revert) MG=$(list_mech_gen); set -x; hg revert $MG; exit;; ---list) list_mech_gen; exit;; ---help|*) echo "Usage: $0 [--generate [file] | --clean | --revert | --list]"; exit 1;; +--help|*) echo "Usage: $0 [--generate [file]]"; exit 1;; esac . config.sh diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Int128VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Int128VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Int128VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Int128VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3229,13 +3229,16 @@ int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Int256VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Int256VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Int256VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Int256VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3229,13 +3229,16 @@ int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Int512VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Int512VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Int512VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Int512VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3229,13 +3229,16 @@ int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Int64VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Int64VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Int64VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Int64VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3229,13 +3229,16 @@ int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -231,10 +231,10 @@ } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index) { - int i = 0; + static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3234,13 +3234,16 @@ int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane(0, (int)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (int)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(int a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Long128VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Long128VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Long128VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Long128VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -183,10 +183,10 @@ } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3251,13 +3251,16 @@ long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Long256VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Long256VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Long256VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Long256VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -183,10 +183,10 @@ } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3251,13 +3251,16 @@ long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Long512VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Long512VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Long512VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Long512VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -183,10 +183,10 @@ } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3251,13 +3251,16 @@ long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Long64VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Long64VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Long64VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Long64VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -183,10 +183,10 @@ } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3251,13 +3251,16 @@ long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -188,10 +188,10 @@ } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index) { - int i = 0; + static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3256,13 +3256,16 @@ long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane(0, (long)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (long)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(long a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/run-tests.sh openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/run-tests.sh --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/run-tests.sh 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/run-tests.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. -# 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. -# - -. config.sh - -POSITIONAL=() -while [[ $# -gt 0 ]] -do -key="$1" - -TESTS="" -DISABLE_VECTOR_INTRINSICS=false -case $key in - -t|--tests) - TESTS="$2" - echo "Tests set to $TESTS" - shift # past argument - shift # past value - ;; - -d|--disable-vector-intrinsics) - DISABLE_VECTOR_INTRINSICS=true - echo "Warning: Disabling Vector intrinsics..." - shift # past argument - ;; - *) # unknown option - POSITIONAL+=("$1") # save it in an array for later - shift # past argument - ;; -esac -done -set -- "${POSITIONAL[@]}" # restore positional parameters - - -if [ "$TESTS" == "" ]; then - # Run all the tests by default. - TESTS="Byte64VectorTests,Byte128VectorTests,Byte256VectorTests,Byte512VectorTests," - TESTS+="Int64VectorTests,Int128VectorTests,Int256VectorTests,Int512VectorTests," - TESTS+="Long64VectorTests,Long128VectorTests,Long256VectorTests,Long512VectorTests," - TESTS+="Short64VectorTests,Short128VectorTests,Short256VectorTests,Short512VectorTests," - TESTS+="Double64VectorTests,Double128VectorTests,Double256VectorTests,Double512VectorTests," - TESTS+="Float64VectorTests,Float128VectorTests,Float256VectorTests,Float512VectorTests" -fi - -# Get Java flags. -JAVA_FLAGS="-XX:-TieredCompilation" -if [ "$DISABLE_VECTOR_INTRINSICS" == "true" ]; then - JAVA_FLAGS+=" -XX:-UseVectorApiIntrinsics" -fi - -LogRun false "Running tests $(date)\n" -LogRun true "Running the following tests:\n" -LogRun true "${TESTS}\n" -LogRun false "${JAVA} -cp \"${VECTORTESTS_HOME_CP}${SEPARATOR}${TESTNG_RUN_JAR}${SEPARATOR}${JCOMMANDER_JAR}\" ${JAVA_FLAGS} --add-modules jdk.incubator.vector --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED org.testng.TestNG -testclass $TESTS" - -# Actual TestNG run. -time ${JAVA} -cp "${VECTORTESTS_HOME_CP}${SEPARATOR}${TESTNG_RUN_JAR}${SEPARATOR}${JCOMMANDER_JAR}" \ - ${JAVA_FLAGS} \ - --add-modules jdk.incubator.vector \ - --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED \ - -Djdk.incubator.vector.test.loop-iterations=${TEST_ITER_COUNT} \ - org.testng.TestNG -testclass $TESTS -LogRun true "Tests run complete. Please look at test-output/index.html to visualize the results.\n" - diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Short128VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Short128VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Short128VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Short128VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3254,13 +3254,16 @@ short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Short256VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Short256VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Short256VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Short256VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3254,13 +3254,16 @@ short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Short512VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Short512VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Short512VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Short512VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3254,13 +3254,16 @@ short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Short64VectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Short64VectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/Short64VectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/Short64VectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -226,10 +226,10 @@ } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3254,13 +3254,16 @@ short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -231,10 +231,10 @@ } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index) { - int i = 0; + static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { @@ -3259,13 +3259,16 @@ short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane(0, (short)4).intoArray(r, i); + av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); } } - assertInsertArraysEquals(r, a, (short)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } static boolean testIS_DEFAULT(short a) { return bits(a)==0; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template 2022-07-14 08:05:38.000000000 +0000 @@ -2,9 +2,9 @@ $type$[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { - for (int i = 0; i < a.length; i += SPECIES.length()) { + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - av.withLane(0, ($type$)4).intoArray(r, i); + av.withLane((j++ \& (SPECIES.length()-1)), ($type$)(65535+i)).intoArray(r, i); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/templates/Unit-header.template openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/templates/Unit-header.template --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/templates/Unit-header.template 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/templates/Unit-header.template 2022-07-14 08:05:38.000000000 +0000 @@ -257,10 +257,10 @@ } } - static void assertInsertArraysEquals($type$[] r, $type$[] a, $type$ element, int index) { - int i = 0; + static void assertInsertArraysEquals($type$[] r, $type$[] a, $type$ element, int index, int start, int end) { + int i = start; try { - for (; i < a.length; i += 1) { + for (; i < end; i += 1) { if(i%SPECIES.length() == index) { Assert.assertEquals(r[i], element); } else { diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template 2022-07-14 08:05:38.000000000 +0000 @@ -2,5 +2,8 @@ @Test(dataProvider = "$type$UnaryOpProvider") static void with$vectorteststype$(IntFunction<$type$ []> fa) { [[KERNEL]] - assertInsertArraysEquals(r, a, ($type$)4, 0); + + for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { + assertInsertArraysEquals(r, a, ($type$)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); + } } diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java --- openjdk-17-17.0.3+7/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/incubator/vector/VectorMaxConversionTests.java 2022-07-14 08:05:38.000000000 +0000 @@ -40,6 +40,18 @@ * VectorMaxConversionTests */ +/* + * @test + * @bug 8281544 + * @summary Test that ZGC and vectorapi with KNL work together. + * @requires vm.gc.Z + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.vm.annotation + * @run testng/othervm -XX:-TieredCompilation --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED + * -XX:+UnlockDiagnosticVMOptions -XX:+UseKNLSetting -XX:+UseZGC -XX:+IgnoreUnrecognizedVMOptions + * VectorMaxConversionTests + */ + @Test public class VectorMaxConversionTests extends AbstractVectorConversionTest { diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java openjdk-17-17.0.4+8/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java --- openjdk-17-17.0.3+7/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. All rights reserved. * 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,36 @@ import com.sun.management.OperatingSystemMXBean; import java.lang.management.ManagementFactory; +// Usage: +// GetFreeSwapSpaceSize public class GetFreeSwapSpaceSize { public static void main(String[] args) { - System.out.println("TestGetFreeSwapSpaceSize"); + if (args.length != 4) { + throw new RuntimeException("Unexpected arguments. Expected 4, got " + args.length); + } + String memoryAlloc = args[0]; + long expectedMemory = Long.parseLong(args[1]); + String memorySwapAlloc = args[2]; + long expectedSwap = Long.parseLong(args[3]); + System.out.println("TestGetFreeSwapSpaceSize (memory=" + memoryAlloc + ", memorySwap=" + memorySwapAlloc + ")"); + if (expectedSwap != 0) { + throw new RuntimeException("Precondition of test not met: Expected swap size of 0, got: " + expectedSwap); + } OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + long osBeanTotalSwap = osBean.getTotalSwapSpaceSize(); + // Premise of this test is to test on a system where --memory and --memory-swap are set to + // the same amount via the container engine (i.e. no swap). In that case the OSBean must + // not report negative values for free swap space. Assert this precondition. + if (osBeanTotalSwap != expectedSwap) { + throw new RuntimeException("OperatingSystemMXBean.getTotalSwapSpaceSize() reported " + osBeanTotalSwap + " expected " + expectedSwap); + } + System.out.println("TestGetFreeSwapSpaceSize precondition met, osBeanTotalSwap = " + expectedSwap + ". Running test... "); for (int i = 0; i < 100; i++) { long size = osBean.getFreeSwapSpaceSize(); if (size < 0) { - System.out.println("Error: getFreeSwapSpaceSize returns " + size); - System.exit(-1); + throw new RuntimeException("Test failed! getFreeSwapSpaceSize returns " + size); } } + System.out.println("TestGetFreeSwapSpaceSize PASSED." ); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java openjdk-17-17.0.4+8/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java --- openjdk-17-17.0.3+7/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. All rights reserved. * 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,7 +36,7 @@ import jdk.test.lib.process.OutputAnalyzer; public class TestGetFreeSwapSpaceSize { - private static final String imageName = Common.imageName("memory"); + private static final String imageName = Common.imageName("osbeanSwapSpace"); public static void main(String[] args) throws Exception { if (!DockerTestUtils.canTestDocker()) { @@ -58,17 +58,18 @@ } private static void testGetFreeSwapSpaceSize(String memoryAllocation, String expectedMemory, - String swapAllocation, String expectedSwap) throws Exception { + String memorySwapAllocation, String expectedSwap) throws Exception { Common.logNewTestCase("TestGetFreeSwapSpaceSize"); DockerRunOptions opts = Common.newOpts(imageName, "GetFreeSwapSpaceSize") + .addClassOptions(memoryAllocation, expectedMemory, memorySwapAllocation, expectedSwap) .addDockerOpts( "--memory", memoryAllocation, - "--memory-swap", swapAllocation + "--memory-swap", memorySwapAllocation ); OutputAnalyzer out = DockerTestUtils.dockerRunJava(opts); out.shouldHaveExitValue(0) - .shouldContain("TestGetFreeSwapSpaceSize"); + .shouldContain("TestGetFreeSwapSpaceSize PASSED."); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java --- openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -37,8 +39,16 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 -Xint jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 + * jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=100k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=1 + * -Xint + * jdk.jfr.event.allocation.TestObjectAllocationInNewTLABEvent */ /** @@ -46,17 +56,19 @@ * an event will be triggered. The test is done for default and interpreted mode (-Xint). * * To force objects to be allocated in a new TLAB: - * the size of TLAB is set to 100k (-XX:TLABSize=100k); - * the size of allocated objects is set to 100k minus 16 bytes overhead; + * the initial size of TLAB is set to 100k (-XX:TLABSize=100k); + * the size of allocated objects is set to 128k; * max TLAB waste at refill is set to minimum (-XX:TLABRefillWasteFraction=1), * to provoke a new TLAB creation. */ public class TestObjectAllocationInNewTLABEvent { private final static String EVENT_NAME = EventNames.ObjectAllocationInNewTLAB; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array. - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops. + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static final int INITIAL_TLAB_SIZE = 100 * 1024; @@ -112,9 +124,9 @@ long allocationSize = Events.assertField(event, "allocationSize").atLeast(1L).getValue(); long tlabSize = Events.assertField(event, "tlabSize").atLeast(allocationSize).getValue(); String className = Events.assertField(event, "objectClass.name").notEmpty().getValue(); - if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE || allocationSize == OBJECT_SIZE_ALT)) { + if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE)) { countAllTlabs++; - if (tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE || tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE_ALT) { + if (tlabSize == INITIAL_TLAB_SIZE + OBJECT_SIZE) { countFullTlabs++; } } diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java --- openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -37,8 +39,16 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent - * @run main/othervm -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 -Xint jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 + * jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=90k -XX:-ResizeTLAB -XX:TLABRefillWasteFraction=256 + * -Xint + * jdk.jfr.event.allocation.TestObjectAllocationOutsideTLABEvent */ /** @@ -46,17 +56,19 @@ * Thread Local Allocation Buffer (TLAB). The test is done for default interpreted mode (-Xint). * * To force objects to be allocated outside TLAB: - * the size of TLAB is set to 90k (-XX:TLABSize=90k); - * the size of allocated objects is set to 100k. + * the initial size of TLAB is set to 90k (-XX:TLABSize=90k); + * the size of allocated objects is set to 128k; * max TLAB waste at refill is set to 256 (-XX:TLABRefillWasteFraction=256), * to prevent a new TLAB creation. */ public class TestObjectAllocationOutsideTLABEvent { private static final String EVENT_NAME = EventNames.ObjectAllocationOutsideTLAB; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static int eventCount; @@ -94,7 +106,7 @@ } long allocationSize = Events.assertField(event, "allocationSize").atLeast(1L).getValue(); String className = Events.assertField(event, "objectClass.name").notEmpty().getValue(); - if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE || allocationSize == OBJECT_SIZE_ALT)) { + if (className.equals(BYTE_ARRAY_CLASS_NAME) && (allocationSize == OBJECT_SIZE)) { ++eventCount; } } diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java --- openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import sun.hotspot.WhiteBox; /** * @test @@ -39,15 +41,22 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib -* @run main/othervm -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB jdk.jfr.event.allocation.TestObjectAllocationSampleEventThrottling + * @build sun.hotspot.WhiteBox + * + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB + * jdk.jfr.event.allocation.TestObjectAllocationSampleEventThrottling */ public class TestObjectAllocationSampleEventThrottling { private static final String EVENT_NAME = EventNames.ObjectAllocationSample; - private static final int BYTE_ARRAY_OVERHEAD = 16; // Extra bytes used by a byte array - private static final int OBJECT_SIZE = 100 * 1024; - private static final int OBJECT_SIZE_ALT = OBJECT_SIZE + 8; // Object size in case of disabled CompressedOops + private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); + + private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + private static final int OBJECT_SIZE = 128 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 100; private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName(); private static int eventCount; diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/gc/detailed/evacuationfailed-testsettings.jfc openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/gc/detailed/evacuationfailed-testsettings.jfc --- openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/gc/detailed/evacuationfailed-testsettings.jfc 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/gc/detailed/evacuationfailed-testsettings.jfc 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ - - - - - - true - 0 ms - - diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/gc/detailed/TestEvacuationFailedEvent.java openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/gc/detailed/TestEvacuationFailedEvent.java --- openjdk-17-17.0.3+7/test/jdk/jdk/jfr/event/gc/detailed/TestEvacuationFailedEvent.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/jfr/event/gc/detailed/TestEvacuationFailedEvent.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * 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,43 +23,59 @@ package jdk.jfr.event.gc.detailed; -import java.io.File; -import java.nio.file.Paths; +import java.lang.ref.Reference; import java.util.List; +import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; -import jdk.jfr.consumer.RecordingFile; import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; +import sun.hotspot.WhiteBox; + /** * @test * @key jfr + * @bug 8263461 * @requires vm.hasJFR * * @library /test/lib /test/jdk * @requires vm.gc == "G1" | vm.gc == null + * @requires vm.debug * - * @run main jdk.jfr.event.gc.detailed.TestEvacuationFailedEvent + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xmx32m -Xms32m -XX:+UnlockExperimentalVMOptions -XX:+G1EvacuationFailureALot + * -XX:G1EvacuationFailureALotCount=100 -XX:G1EvacuationFailureALotInterval=1 + * -Xlog:gc=debug -XX:+UseG1GC jdk.jfr.event.gc.detailed.TestEvacuationFailedEvent */ + public class TestEvacuationFailedEvent { - private final static String EVENT_SETTINGS_FILE = System.getProperty("test.src", ".") + File.separator + "evacuationfailed-testsettings.jfc"; - private final static String JFR_FILE = "TestEvacuationFailedEvent.jfr"; - private final static int BYTES_TO_ALLOCATE = 1024 * 512; + private final static String EVENT_NAME = EventNames.EvacuationFailed; public static void main(String[] args) throws Exception { - String[] vmFlags = {"-XX:+UnlockExperimentalVMOptions", "-XX:-UseFastUnorderedTimeStamps", - "-Xmx64m", "-Xmn60m", "-XX:-UseDynamicNumberOfGCThreads", "-XX:ParallelGCThreads=3", - "-XX:MaxTenuringThreshold=0", "-Xlog:gc*=debug", "-XX:+UseG1GC"}; - - if (!ExecuteOOMApp.execute(EVENT_SETTINGS_FILE, JFR_FILE, vmFlags, BYTES_TO_ALLOCATE)) { - System.out.println("OOM happened in the other thread(not test thread). Skip test."); - // Skip test, process terminates due to the OOME error in the different thread - return; + Recording recording = new Recording(); + // activate the event we are interested in and start recording + recording.enable(EVENT_NAME); + recording.start(); + + Object[] data = new Object[1024]; + + for (int i = 0; i < data.length; i++) { + data[i] = new byte[5 * 1024]; } + // Guarantee one young gc. + WhiteBox.getWhiteBox().youngGC(); + // Keep alive data. + Reference.reachabilityFence(data); + + recording.stop(); - List events = RecordingFile.readAllEvents(Paths.get(JFR_FILE)); + // Verify recording + List events = Events.fromRecording(recording); Events.hasEvents(events); for (RecordedEvent event : events) { @@ -69,5 +85,6 @@ long totalSize = Events.assertField(event, "evacuationFailed.totalSize").atLeast(firstSize).getValue(); Asserts.assertLessThanOrEqual(smallestSize * objectCount, totalSize, "smallestSize * objectCount <= totalSize"); } + recording.close(); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/security/jarsigner/JarWithOneNonDisabledDigestAlg.java openjdk-17-17.0.4+8/test/jdk/jdk/security/jarsigner/JarWithOneNonDisabledDigestAlg.java --- openjdk-17-17.0.3+7/test/jdk/jdk/security/jarsigner/JarWithOneNonDisabledDigestAlg.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/security/jarsigner/JarWithOneNonDisabledDigestAlg.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8278851 + * @summary Check that jar entry with at least one non-disabled digest + * algorithm in manifest is treated as signed + * @modules java.base/sun.security.tools.keytool + * @library /test/lib + * @build jdk.test.lib.util.JarUtils + * jdk.test.lib.security.SecurityUtils + * @run main/othervm JarWithOneNonDisabledDigestAlg + */ + +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.CodeSigner; +import java.security.KeyStore; +import java.util.Enumeration; +import java.util.List; +import java.util.Locale; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipFile; +import jdk.security.jarsigner.JarSigner; + +import jdk.test.lib.util.JarUtils; +import jdk.test.lib.security.SecurityUtils; + +public class JarWithOneNonDisabledDigestAlg { + + private static final String PASS = "changeit"; + private static final String TESTFILE1 = "testfile1"; + private static final String TESTFILE2 = "testfile2"; + + public static void main(String[] args) throws Exception { + SecurityUtils.removeFromDisabledAlgs("jdk.jar.disabledAlgorithms", + List.of("SHA1")); + Files.write(Path.of(TESTFILE1), TESTFILE1.getBytes()); + JarUtils.createJarFile(Path.of("unsigned.jar"), Path.of("."), + Path.of(TESTFILE1)); + + genkeypair("-alias SHA1 -sigalg SHA1withRSA"); + genkeypair("-alias SHA256 -sigalg SHA256withRSA"); + + KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + try (FileInputStream fis = new FileInputStream("keystore")) { + ks.load(fis, PASS.toCharArray()); + } + + // Sign JAR twice with same signer but different digest algorithms + // so that each entry in manifest file contains two digest values. + signJarFile(ks, "SHA1", "MD5", "unsigned.jar", "signed.jar"); + signJarFile(ks, "SHA1", "SHA1", "signed.jar", "signed2.jar"); + checkThatJarIsSigned("signed2.jar", false); + + // add another file to the JAR + Files.write(Path.of(TESTFILE2), "testFile2".getBytes()); + JarUtils.updateJarFile(Path.of("signed2.jar"), Path.of("."), + Path.of(TESTFILE2)); + + // Sign again with different signer (SHA256) and SHA-1 digestalg. + // TESTFILE1 should have two signers and TESTFILE2 should have one + // signer. + signJarFile(ks, "SHA256", "SHA1", "signed2.jar", "multi-signed.jar"); + + checkThatJarIsSigned("multi-signed.jar", true); + } + + private static KeyStore.PrivateKeyEntry getEntry(KeyStore ks, String alias) + throws Exception { + + return (KeyStore.PrivateKeyEntry) + ks.getEntry(alias, + new KeyStore.PasswordProtection(PASS.toCharArray())); + } + + private static void genkeypair(String cmd) throws Exception { + cmd = "-genkeypair -keystore keystore -storepass " + PASS + + " -keypass " + PASS + " -keyalg rsa -dname CN=Duke " + cmd; + sun.security.tools.keytool.Main.main(cmd.split(" ")); + } + + private static void signJarFile(KeyStore ks, String alias, + String digestAlg, String inputFile, String outputFile) + throws Exception { + + JarSigner signer = new JarSigner.Builder(getEntry(ks, alias)) + .digestAlgorithm(digestAlg) + .signerName(alias) + .build(); + + try (ZipFile in = new ZipFile(inputFile); + FileOutputStream out = new FileOutputStream(outputFile)) { + signer.sign(in, out); + } + } + + private static void checkThatJarIsSigned(String jarFile, boolean multi) + throws Exception { + + try (JarFile jf = new JarFile(jarFile, true)) { + Enumeration entries = jf.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.isDirectory() || isSigningRelated(entry.getName())) { + continue; + } + InputStream is = jf.getInputStream(entry); + while (is.read() != -1); + CodeSigner[] signers = entry.getCodeSigners(); + if (signers == null) { + throw new Exception("JarEntry " + entry.getName() + + " is not signed"); + } else if (multi) { + if (entry.getName().equals(TESTFILE1) && + signers.length != 2) { + throw new Exception("Unexpected number of signers " + + "for " + entry.getName() + ": " + signers.length); + } else if (entry.getName().equals(TESTFILE2) && + signers.length != 1) { + throw new Exception("Unexpected number of signers " + + "for " + entry.getName() + ": " + signers.length); + } + } + } + } + } + + private static boolean isSigningRelated(String name) { + name = name.toUpperCase(Locale.ENGLISH); + if (!name.startsWith("META-INF/")) { + return false; + } + name = name.substring(9); + if (name.indexOf('/') != -1) { + return false; + } + return name.endsWith(".SF") + || name.endsWith(".DSA") + || name.endsWith(".RSA") + || name.endsWith(".EC") + || name.equals("MANIFEST.MF"); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/security/JavaDotSecurity/ifdefs.sh openjdk-17-17.0.4+8/test/jdk/jdk/security/JavaDotSecurity/ifdefs.sh --- openjdk-17-17.0.3+7/test/jdk/jdk/security/JavaDotSecurity/ifdefs.sh 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/security/JavaDotSecurity/ifdefs.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +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 8141690 -# @summary MakeJavaSecurity.java functions - -if [ "${TESTSRC}" = "" ] ; then - TESTSRC="." -fi - -if [ "${TESTJAVA}" = "" ] ; then - JAVAC_CMD=`which javac` - TESTJAVA=`dirname $JAVAC_CMD`/.. - COMPILEJAVA=${TESTJAVA} -fi - -JAVAC="${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS}" -JAVA="${TESTJAVA}/bin/java ${TESTVMOPTS}" -TOOLSRC="${TESTSRC}/../../../../make/src/classes/build/tools/makejavasecurity/MakeJavaSecurity.java" -TOOLNAME=build.tools.makejavasecurity.MakeJavaSecurity - -if [ ! -f $TOOLSRC ]; then - echo "Cannot find $TOOLSRC. Maybe not all code repos are available" - exit 0 -fi - -$JAVAC -d . $TOOLSRC -$JAVA $TOOLNAME \ - $TESTSRC/raw_java_security \ - outfile \ - solaris \ - sparc \ - somepolicy \ - $TESTSRC/more_restricted - -# On Windows, line end could be different. -b is a cross-platform option. -diff -b outfile $TESTSRC/final_java_security diff -Nru openjdk-17-17.0.3+7/test/jdk/jdk/security/JavaDotSecurity/MakeJavaSecurityTest.java openjdk-17-17.0.4+8/test/jdk/jdk/security/JavaDotSecurity/MakeJavaSecurityTest.java --- openjdk-17-17.0.3+7/test/jdk/jdk/security/JavaDotSecurity/MakeJavaSecurityTest.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/jdk/security/JavaDotSecurity/MakeJavaSecurityTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +import jdk.test.lib.Asserts; + +/** + * @test + * @bug 8141690 + * @summary MakeJavaSecurity.java functions + * @library /test/lib /test/jdk + * @run main MakeJavaSecurityTest + */ +public class MakeJavaSecurityTest { + + private static final String TEST_SRC = System.getProperty("test.src", "."); + + public static void main(String[] args) throws Exception { + Path toolPath = getMakeJavaSecPath(); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + toolPath.toString(), + TEST_SRC + "/raw_java_security", + "outfile", + "solaris", + "sparc", + "somepolicy", + TEST_SRC + "/more_restricted"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + verifyOutputFile(); + } + + private static Path getMakeJavaSecPath() { + String testRoot = System.getProperty("test.root", "."); + Path toolPath = Paths.get(testRoot).getParent().getParent(); + toolPath = toolPath.resolve("make/jdk/src/classes/build/tools" + + "/makejavasecurity/MakeJavaSecurity.java"); + + Asserts.assertTrue(Files.exists(toolPath), + String.format("Cannot find %s. Maybe not all code repos are available", + toolPath)); + return toolPath; + } + + private static void verifyOutputFile() throws IOException { + Path actualFile = Path.of("./outfile"); + Path expectedFile = Path.of(TEST_SRC + "/final_java_security"); + + List list1 = Files.readAllLines(actualFile); + List list2 = Files.readAllLines(expectedFile); + list1 = removeEmptyLines(list1); + list2 = removeEmptyLines(list2); + + String errorMessage = String.format(""" + Expected file content: + %s\s + not equal to actual: + %s\s + """, list2, list1); + + Asserts.assertTrue(list1.equals(list2), errorMessage); + } + + private static List removeEmptyLines(List list) { + return list.stream() + .filter(item -> !item.isBlank()) + .collect(Collectors.toList()); + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/ProblemList.txt openjdk-17-17.0.4+8/test/jdk/ProblemList.txt --- openjdk-17-17.0.3+7/test/jdk/ProblemList.txt 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/ProblemList.txt 2022-07-14 08:05:38.000000000 +0000 @@ -619,7 +619,7 @@ java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64 -java/nio/channels/Selector/Wakeup.java 6963118 windows-all +java/nio/channels/DatagramChannel/ManySourcesAndTargets.java 8264385 macosx-aarch64 ############################################################################ @@ -686,6 +686,7 @@ sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java 8039280 generic-all sun/security/provider/PolicyParser/ExtDirsChange.java 8039280 generic-all sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic-all +sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java 8277970 linux-all,macosx-x64 ############################################################################ @@ -824,7 +825,6 @@ jdk/jfr/event/os/TestThreadContextSwitches.java 8247776 windows-all jdk/jfr/startupargs/TestStartName.java 8214685 windows-x64 jdk/jfr/startupargs/TestStartDuration.java 8214685 windows-x64 -jdk/jfr/event/gc/detailed/TestEvacuationFailedEvent.java 8263461 linux-all,windows-x64 jdk/jfr/api/consumer/streaming/TestLatestEvent.java 8268297 windows-x64 ############################################################################ diff -Nru openjdk-17-17.0.3+7/test/jdk/ProblemList-Xcomp.txt openjdk-17-17.0.4+8/test/jdk/ProblemList-Xcomp.txt --- openjdk-17-17.0.3+7/test/jdk/ProblemList-Xcomp.txt 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/ProblemList-Xcomp.txt 2022-07-14 08:05:38.000000000 +0000 @@ -28,4 +28,3 @@ ############################################################################# java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all -java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorTest.java 8256368 generic-all diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/net/ftp/TestFtpTimeValue.java openjdk-17-17.0.4+8/test/jdk/sun/net/ftp/TestFtpTimeValue.java --- openjdk-17-17.0.3+7/test/jdk/sun/net/ftp/TestFtpTimeValue.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/net/ftp/TestFtpTimeValue.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,7 +116,7 @@ public void handleClient(Socket client) throws IOException { String str; - client.setSoTimeout(2000); + client.setSoTimeout(10000); BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out = new PrintWriter(client.getOutputStream(), true); out.println("220 FTP serverSocket is ready."); diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/net/www/protocol/http/B6296310.java openjdk-17-17.0.4+8/test/jdk/sun/net/www/protocol/http/B6296310.java --- openjdk-17-17.0.3+7/test/jdk/sun/net/www/protocol/http/B6296310.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/net/www/protocol/http/B6296310.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * 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,17 +24,30 @@ /* * @test * @bug 6296310 - * @modules java.base/sun.net.www - * @library ../../httptest/ - * @build HttpCallback TestHttpServer HttpTransaction + * @library /test/lib * @run main/othervm B6296310 * @run main/othervm -Djava.net.preferIPv6Addresses=true B6296310 * @summary REGRESSION: AppletClassLoader.getResourceAsStream() behaviour is wrong in some cases */ -import java.net.*; -import java.io.*; -import java.util.*; +import java.io.IOException; +import java.io.OutputStream; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ResponseCache; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.Map; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; /* * http server returns 200 and content-length=0 @@ -44,7 +57,7 @@ public class B6296310 { static SimpleHttpTransaction httpTrans; - static TestHttpServer server; + static HttpServer server; public static void main(String[] args) throws Exception { @@ -56,31 +69,35 @@ public static void startHttpServer() throws IOException { httpTrans = new SimpleHttpTransaction(); InetAddress loopback = InetAddress.getLoopbackAddress(); - server = new TestHttpServer(httpTrans, 1, 10, loopback, 0); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/", httpTrans); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); } public static void makeHttpCall() throws IOException { try { - System.out.println("http server listen on: " + server.getLocalPort()); + System.out.println("http server listen on: " + server.getAddress().getPort()); URL url = new URL("http" , InetAddress.getLoopbackAddress().getHostAddress(), - server.getLocalPort(), "/"); + server.getAddress().getPort(), "/"); HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); System.out.println(uc.getResponseCode()); } finally { - server.terminate(); + server.stop(1); } } } -class SimpleHttpTransaction implements HttpCallback +class SimpleHttpTransaction implements HttpHandler { /* * Our http server which simply retruns a file with no content */ - public void request(HttpTransaction trans) { + @Override + public void handle(HttpExchange trans) { try { - trans.setResponseEntityBody(""); - trans.sendResponse(200, "OK"); + trans.sendResponseHeaders(200, 0); + trans.close(); } catch (Exception e) { e.printStackTrace(); } diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/net/www/protocol/http/RelativeRedirect.java openjdk-17-17.0.4+8/test/jdk/sun/net/www/protocol/http/RelativeRedirect.java --- openjdk-17-17.0.3+7/test/jdk/sun/net/www/protocol/http/RelativeRedirect.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/net/www/protocol/http/RelativeRedirect.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * 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,20 +24,32 @@ /** * @test * @bug 4726087 - * @modules java.base/sun.net.www - * @library ../../httptest/ - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction - * @run main RelativeRedirect + * @library /test/lib + * @run main/othervm RelativeRedirect * @run main/othervm -Djava.net.preferIPv6Addresses=true RelativeRedirect * @summary URLConnection cannot handle redirects */ -import java.io.*; -import java.net.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.Authenticator; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.net.URL; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; -public class RelativeRedirect implements HttpCallback { +public class RelativeRedirect implements HttpHandler { static int count = 0; - static TestHttpServer server; + static HttpServer server; + static class MyAuthenticator extends Authenticator { public MyAuthenticator () { @@ -50,26 +62,29 @@ } } - void firstReply (HttpTransaction req) throws IOException { - req.addResponseHeader ("Connection", "close"); - req.addResponseHeader ("Location", "/redirect/file.html"); - req.sendResponse (302, "Moved Permamently"); - req.orderlyClose(); + void firstReply(HttpExchange req) throws IOException { + req.getResponseHeaders().set("Connection", "close"); + req.getResponseHeaders().set("Location", "/redirect/file.html"); + req.sendResponseHeaders(302, -1); } - void secondReply (HttpTransaction req) throws IOException { + void secondReply (HttpExchange req) throws IOException { if (req.getRequestURI().toString().equals("/redirect/file.html") && - req.getRequestHeader("Host").equals(authority(server.getLocalPort()))) { - req.setResponseEntityBody ("Hello ."); - req.sendResponse (200, "Ok"); + req.getRequestHeaders().get("Host").get(0).equals(authority(server.getAddress().getPort()))) { + req.sendResponseHeaders(200, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody())) { + pw.print("Hello ."); + } } else { - req.setResponseEntityBody (req.getRequestURI().toString()); - req.sendResponse (400, "Bad request"); + req.sendResponseHeaders(400, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody())) { + pw.print(req.getRequestURI().toString()); + } } - req.orderlyClose(); - } - public void request (HttpTransaction req) { + + @Override + public void handle (HttpExchange req) { try { switch (count) { case 0: @@ -101,9 +116,12 @@ MyAuthenticator auth = new MyAuthenticator (); Authenticator.setDefault (auth); try { - server = new TestHttpServer (new RelativeRedirect(), 1, 10, loopback, 0); - System.out.println ("Server: listening on port: " + server.getLocalPort()); - URL url = new URL("http://" + authority(server.getLocalPort())); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/", new RelativeRedirect()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + System.out.println ("Server: listening on port: " + server.getAddress().getPort()); + URL url = new URL("http://" + authority(server.getAddress().getPort())); System.out.println ("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (Proxy.NO_PROXY); InputStream is = urlc.getInputStream (); @@ -112,7 +130,7 @@ throw new RuntimeException(e); } finally { if (server != null) { - server.terminate(); + server.stop(1); } } } diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java openjdk-17-17.0.4+8/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java --- openjdk-17-17.0.3+7/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * 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,33 +25,48 @@ * @test * @bug 6262486 * @library /test/lib - * @modules java.base/sun.net.www - * @library ../../httptest/ - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction * @run main/othervm -Dhttp.keepAlive=false ResponseCacheStream * @summary COMPATIBILITY: jagex_com - Monkey Puzzle applet fails to load */ -import java.net.*; -import java.io.*; -import java.util.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ResponseCache; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -public class ResponseCacheStream implements HttpCallback { +public class ResponseCacheStream implements HttpHandler { - void okReply (HttpTransaction req) throws IOException { - req.setResponseEntityBody ("Hello, This is the response body. Let's make it as long as possible since we need to test the cache mechanism."); - req.sendResponse (200, "Ok"); - System.out.println ("Server: sent response"); - req.orderlyClose(); + void okReply (HttpExchange req) throws IOException { + req.sendResponseHeaders(200, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody())) { + pw.print("Hello, This is the response body. Let's make it as long as possible since we need to test the cache mechanism."); + } + System.out.println ("Server: sent response"); } - public void request (HttpTransaction req) { - try { - okReply (req); - } catch (IOException e) { - e.printStackTrace(); - } + + @Override + public void handle(HttpExchange exchange) throws IOException { + okReply(exchange); + exchange.close(); } static class MyCacheRequest extends CacheRequest { @@ -94,19 +109,22 @@ } } - static TestHttpServer server; + static HttpServer server; public static void main(String[] args) throws Exception { MyResponseCache cache = new MyResponseCache(); try { InetAddress loopback = InetAddress.getLoopbackAddress(); ResponseCache.setDefault(cache); - server = new TestHttpServer (new ResponseCacheStream(), loopback, 0); - System.out.println ("Server: listening on port: " + server.getLocalPort()); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/", new ResponseCacheStream()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + System.out.println("Server: listening on port: " + server.getAddress().getPort()); URL url = URIBuilder.newBuilder() .scheme("http") .loopback() - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .path("/") .toURL(); System.out.println ("Client: connecting to " + url); @@ -149,10 +167,10 @@ } } catch (Exception e) { if (server != null) { - server.terminate(); + server.stop(1); } throw e; } - server.terminate(); + server.stop(1); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/net/www/protocol/http/SetChunkedStreamingMode.java openjdk-17-17.0.4+8/test/jdk/sun/net/www/protocol/http/SetChunkedStreamingMode.java --- openjdk-17-17.0.3+7/test/jdk/sun/net/www/protocol/http/SetChunkedStreamingMode.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/net/www/protocol/http/SetChunkedStreamingMode.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. * 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,56 +24,54 @@ /** * @test * @bug 5049976 - * @modules java.base/sun.net.www - * @library ../../httptest/ * @library /test/lib - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction - * @run main SetChunkedStreamingMode + * @run main/othervm SetChunkedStreamingMode * @summary Unspecified NPE is thrown when streaming output mode is enabled */ -import java.io.*; -import java.net.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URL; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -public class SetChunkedStreamingMode implements HttpCallback { +public class SetChunkedStreamingMode implements HttpHandler { - void okReply (HttpTransaction req) throws IOException { - req.setResponseEntityBody ("Hello ."); - req.sendResponse (200, "Ok"); - System.out.println ("Server: sent response"); - req.orderlyClose(); - } - - public void request (HttpTransaction req) { - try { - okReply (req); - } catch (IOException e) { - e.printStackTrace(); + void okReply (HttpExchange req) throws IOException { + req.sendResponseHeaders(200, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody())) { + pw.print("Hello ."); } + System.out.println ("Server: sent response"); } - static void read (InputStream is) throws IOException { - int c; - System.out.println ("reading"); - while ((c=is.read()) != -1) { - System.out.write (c); - } - System.out.println (""); - System.out.println ("finished reading"); + @Override + public void handle(HttpExchange exchange) throws IOException { + okReply(exchange); } - static TestHttpServer server; + static HttpServer server; public static void main (String[] args) throws Exception { try { - server = new TestHttpServer(new SetChunkedStreamingMode(), 1, 10, - InetAddress.getLoopbackAddress(), 0); - System.out.println ("Server: listening on port: " + server.getLocalPort()); + InetAddress loopback = InetAddress.getLoopbackAddress(); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/", new SetChunkedStreamingMode()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + System.out.println ("Server: listening on port: " + server.getAddress().getPort()); URL url = URIBuilder.newBuilder() .scheme("http") .loopback() - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .path("/") .toURL(); System.out.println ("Client: connecting to " + url); @@ -84,15 +82,15 @@ InputStream is = urlc.getInputStream(); } catch (Exception e) { if (server != null) { - server.terminate(); + server.stop(1); } throw e; } - server.terminate(); + server.stop(1); } public static void except (String s) { - server.terminate(); + server.stop(1); throw new RuntimeException (s); } } diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/ec/ECDSAJavaVerify.java openjdk-17-17.0.4+8/test/jdk/sun/security/ec/ECDSAJavaVerify.java --- openjdk-17-17.0.3+7/test/jdk/sun/security/ec/ECDSAJavaVerify.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/ec/ECDSAJavaVerify.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * 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 com.sun.jdi.Bootstrap; -import com.sun.jdi.VMDisconnectedException; -import com.sun.jdi.VirtualMachine; -import com.sun.jdi.connect.Connector; -import com.sun.jdi.connect.LaunchingConnector; -import com.sun.jdi.event.Event; -import com.sun.jdi.event.EventSet; -import com.sun.jdi.event.MethodEntryEvent; -import com.sun.jdi.request.MethodEntryRequest; - -import java.security.AlgorithmParameters; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.SecureRandom; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.ECParameterSpec; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Random; - -/* - * @test - * @bug 8237218 8239928 - * @modules jdk.crypto.ec - * jdk.jdi - * @requires os.family != "windows" - * @run main ECDSAJavaVerify debug - * @summary Support NIST Curves verification in java implementation. - * This test does not run stable on Windows. VMDisconnectedException - * might not be thrown at all. - */ - -// ATTENTION: This test depends on method names inside the non-exported -// class sun.security.ec.ECDSASignature. -public class ECDSAJavaVerify { - - static final String[] ALL_ALGS = new String[] { - "SHA1withECDSA", "SHA256withECDSA", "SHA384withECDSA", "SHA512withECDSA"}; - - static final String[] ALL_CURVES = new String[] { - "secp256r1", "secp384r1", "secp521r1"}; - - public static void main(String[] args) throws Exception { - if (args.length == 1) { - // Debugging a new process with no arg - debug(); - } else if (args.length == 3) { - // If one test case fail, re-run it with first 3 columns - new Test().run(Integer.parseInt(args[0]), args[1], args[2]); - } else { - // Run all test cases - Test t = new Test(); - Random r = new Random(); - - for (String sigAlg : ALL_ALGS) { - for (String curve : ALL_CURVES) { - t.run(r.nextInt(1000000), sigAlg, curve); - } - } - } - } - - static void debug() throws Exception { - - LaunchingConnector launchingConnector = Bootstrap - .virtualMachineManager().defaultConnector(); - - Map arguments - = launchingConnector.defaultArguments(); - arguments.get("main").setValue(ECDSAJavaVerify.class.getName()); - arguments.get("options").setValue( - "-cp " + System.getProperty("test.classes")); - VirtualMachine vm = launchingConnector.launch(arguments); - - MethodEntryRequest req = vm.eventRequestManager() - .createMethodEntryRequest(); - req.addClassFilter("sun.security.ec.ECDSASignature"); - req.enable(); - - int numberOfTests = ALL_ALGS.length * ALL_CURVES.length * 2; - - // Expected methods to call. 'J' for java impl, 'N' for native impl - char[] expected = new char[numberOfTests]; - - int pos = 0; - for (String dummy : ALL_ALGS) { - for (String curve : ALL_CURVES) { - char caller = 'J'; - // For each case, Signature::verify is called twice - expected[pos++] = caller; - expected[pos++] = caller; - } - } - - // Test result - // '.': not run yet - // '-': enter engineVerify - // 'v': expected impl called - // 'x': unexpected impl called - // Note: some error cases fail before any impl called. Ex: if there - // is a DER encoding error. - char[] result = new char[numberOfTests]; - Arrays.fill(result, '.'); - - String stdout, stderr; - - try { - EventSet eventSet; - pos = -1; // will become 0 when entering 'engineVerify' - while ((eventSet = vm.eventQueue().remove()) != null) { - for (Event event : eventSet) { - if (event instanceof MethodEntryEvent) { - MethodEntryEvent e = (MethodEntryEvent)event; - switch (e.method().name()) { - case "engineVerify": - result[++pos] = '-'; - break; - case "verifySignedDigestImpl": // the java impl - result[pos] = expected[pos] != 'J' ? 'x' : 'v'; - break; - } - } - vm.resume(); - } - } - } catch (VMDisconnectedException e) { - System.out.println("Virtual Machine is disconnected."); - } finally { - stderr = new String(vm.process().getErrorStream().readAllBytes()); - stdout = new String(vm.process().getInputStream().readAllBytes()); - } - - int exitCode = vm.process().waitFor(); - System.out.println(" exit: " + exitCode); - System.out.println("stderr:\n" + stderr); - System.out.println("stdout:\n" + stdout); - - String sResult = new String(result); - - System.out.println(" Cases: " + new String(expected)); - System.out.println("Result: " + sResult); - - if (pos != numberOfTests - 1 || sResult.contains("x") - || sResult.contains(".")) { - throw new Exception("Unexpected result"); - } - - if (stdout.contains("fail") || exitCode != 0) { - throw new Exception("Test failed"); - } - } - - static class Test { - - public boolean run(int seed, String sigAlg, String curve) - throws Exception { - - // A determined SecureRandom based on seed. If there is anything - // wrong, we can reproduce the problem using the seed. - Random r = new Random(seed); - SecureRandom rand = new SecureRandom() { - @Override - public void nextBytes(byte[] bytes) { - r.nextBytes(bytes); - } - }; - - AlgorithmParameters ap = AlgorithmParameters.getInstance("EC", "SunEC"); - ap.init(new ECGenParameterSpec(curve)); - ECParameterSpec spec = ap.getParameterSpec(ECParameterSpec.class); - - KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "SunEC"); - kpg.initialize(spec, rand); - KeyPair kp = kpg.generateKeyPair(); - ECPrivateKey ecPrivateKey = (ECPrivateKey) kp.getPrivate(); - ECPublicKey ecPublicKey = (ECPublicKey) kp.getPublic(); - - Signature s1 = Signature.getInstance(sigAlg, "SunEC"); - s1.initSign(ecPrivateKey, rand); - byte[] msg = new byte[1234]; - rand.nextBytes(msg); - s1.update(msg); - byte[] sig = s1.sign(); - - Signature s2 = Signature.getInstance(sigAlg, "SunEC"); - s2.initVerify(ecPublicKey); - s2.update(msg); - - boolean result1 = s2.verify(sig); - - s2.initVerify(ecPublicKey); - // modify the signature in some random manner - if (rand.nextInt(10) < 8) { - sig[rand.nextInt(10000) % sig.length] - = (byte) rand.nextInt(10000); - } else { - int newLength = rand.nextInt(100); - if (newLength == sig.length) { - newLength += 1 + rand.nextInt(2); - } - sig = Arrays.copyOf(sig, newLength); - } - - boolean result2; - try { - result2 = s2.verify(sig); - } catch (SignatureException se) { - result2 = false; - } - - boolean finalResult = result1 && !result2; - System.out.printf("%10d %20s %20s -- %5s %5s -- %s\n", - seed, sigAlg, curve, result1, result2, - finalResult ? "succeed" : "fail"); - - return finalResult; - } - } -} diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/krb5/auto/HttpsCB.java openjdk-17-17.0.4+8/test/jdk/sun/security/krb5/auto/HttpsCB.java --- openjdk-17-17.0.3+7/test/jdk/sun/security/krb5/auto/HttpsCB.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/krb5/auto/HttpsCB.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * 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 8279842 8282293 + * @modules java.base/sun.security.util + * java.security.jgss/sun.security.jgss + * java.security.jgss/sun.security.jgss.krb5 + * java.security.jgss/sun.security.jgss.krb5.internal + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal.ccache + * java.security.jgss/sun.security.krb5.internal.crypto + * java.security.jgss/sun.security.krb5.internal.ktab + * jdk.security.auth + * jdk.security.jgss + * jdk.httpserver + * @summary HTTPS Channel Binding support for Java GSS/Kerberos + * @library /test/lib + * @run main jdk.test.lib.FileInstaller TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=always HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=never HttpsCB false true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=invalid HttpsCB false true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * HttpsCB false true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:other.com HttpsCB false true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:host.web.domain HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:HOST.WEB.DOMAIN HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:*.web.domain HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:*.WEB.Domain HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:*.Invalid,*.WEB.Domain HttpsCB true true + */ + +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpPrincipal; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsExchange; +import com.sun.net.httpserver.HttpsServer; +import com.sun.security.auth.module.Krb5LoginModule; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.net.Socket; +import java.net.URL; +import java.security.cert.X509Certificate; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; +import java.util.Map; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509ExtendedTrustManager; +import javax.security.auth.Subject; + +import jdk.test.lib.Asserts; +import jdk.test.lib.net.SimpleSSLContext; +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSCredential; +import org.ietf.jgss.GSSManager; +import sun.security.jgss.GSSUtil; +import sun.security.jgss.krb5.internal.TlsChannelBindingImpl; +import sun.security.krb5.Config; +import sun.security.util.TlsChannelBinding; + +import java.util.Base64; +import java.util.concurrent.Callable; + +public class HttpsCB { + + final static String REALM_WEB = "WEB.DOMAIN"; + final static String KRB5_CONF = "web.conf"; + final static String KRB5_TAB = "web.ktab"; + + final static String WEB_USER = "web"; + final static char[] WEB_PASS = "webby".toCharArray(); + final static String WEB_HOST = "host.web.domain"; + final static String CONTENT = "Hello, World!"; + + static int webPort; + static URL cbtURL; + static URL normalURL; + + public static void main(String[] args) + throws Exception { + + boolean expectCBT = Boolean.parseBoolean(args[0]); + boolean expectNoCBT = Boolean.parseBoolean(args[1]); + + System.setProperty("sun.security.krb5.debug", "true"); + + KDC kdcw = KDC.create(REALM_WEB); + kdcw.addPrincipal(WEB_USER, WEB_PASS); + kdcw.addPrincipalRandKey("krbtgt/" + REALM_WEB); + kdcw.addPrincipalRandKey("HTTP/" + WEB_HOST); + + KDC.saveConfig(KRB5_CONF, kdcw, + "default_keytab_name = " + KRB5_TAB, + "[domain_realm]", + "", + ".web.domain="+REALM_WEB); + + System.setProperty("java.security.krb5.conf", KRB5_CONF); + Config.refresh(); + KDC.writeMultiKtab(KRB5_TAB, kdcw); + + // Write a customized JAAS conf file, so that any kinit cache + // will be ignored. + System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF); + File f = new File(OneKDC.JAAS_CONF); + FileOutputStream fos = new FileOutputStream(f); + fos.write(( + "com.sun.security.jgss.krb5.initiate {\n" + + " com.sun.security.auth.module.Krb5LoginModule required;\n};\n" + ).getBytes()); + fos.close(); + + HttpServer h1 = httpd("Negotiate", + "HTTP/" + WEB_HOST + "@" + REALM_WEB, KRB5_TAB); + webPort = h1.getAddress().getPort(); + + cbtURL = new URL("https://" + WEB_HOST +":" + webPort + "/cbt"); + normalURL = new URL("https://" + WEB_HOST +":" + webPort + "/normal"); + + java.net.Authenticator.setDefault(new java.net.Authenticator() { + public PasswordAuthentication getPasswordAuthentication () { + return new PasswordAuthentication( + WEB_USER+"@"+REALM_WEB, WEB_PASS); + } + }); + + // Client-side SSLContext needs to ignore hostname mismatch + // and untrusted certificate. + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, new TrustManager[] { + new X509ExtendedTrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + public void checkClientTrusted(X509Certificate[] chain, + String authType, Socket socket) { } + public void checkServerTrusted(X509Certificate[] chain, + String authType, Socket socket) { } + public void checkClientTrusted(X509Certificate[] chain, + String authType, SSLEngine engine) { } + public void checkServerTrusted(X509Certificate[] chain, + String authType, SSLEngine engine) { } + public void checkClientTrusted(X509Certificate[] certs, + String authType) { } + public void checkServerTrusted(X509Certificate[] certs, + String authType) { } + } + }, null); + + Asserts.assertEQ(visit(sc, cbtURL), expectCBT); + Asserts.assertEQ(visit(sc, normalURL), expectNoCBT); + } + + static boolean visit(SSLContext sc, URL url) { + try { + HttpsURLConnection conn = (HttpsURLConnection) + url.openConnection(Proxy.NO_PROXY); + conn.setSSLSocketFactory(sc.getSocketFactory()); + BufferedReader reader; + reader = new BufferedReader(new InputStreamReader( + conn.getInputStream())); + return reader.readLine().equals(CONTENT); + } catch (IOException e) { + e.printStackTrace(System.out); + return false; + } + } + + static HttpServer httpd(String scheme, String principal, String ktab) + throws Exception { + MyHttpHandler h = new MyHttpHandler(); + HttpsServer server = HttpsServer.create(new InetSocketAddress(0), 0); + server.setHttpsConfigurator( + new HttpsConfigurator(new SimpleSSLContext().get())); + server.createContext("/", h).setAuthenticator( + new MyServerAuthenticator(scheme, principal, ktab)); + server.start(); + return server; + } + + static class MyHttpHandler implements HttpHandler { + public void handle(HttpExchange t) throws IOException { + t.sendResponseHeaders(200, 0); + t.getResponseBody().write(CONTENT.getBytes()); + t.close(); + } + } + + static class MyServerAuthenticator + extends com.sun.net.httpserver.Authenticator { + Subject s = new Subject(); + GSSManager m; + GSSCredential cred; + String scheme = null; + String reqHdr = "WWW-Authenticate"; + String respHdr = "Authorization"; + int err = HttpURLConnection.HTTP_UNAUTHORIZED; + + public MyServerAuthenticator(String scheme, + String principal, String ktab) throws Exception { + + this.scheme = scheme; + Krb5LoginModule krb5 = new Krb5LoginModule(); + Map map = new HashMap<>(); + Map shared = new HashMap<>(); + + map.put("storeKey", "true"); + map.put("isInitiator", "false"); + map.put("useKeyTab", "true"); + map.put("keyTab", ktab); + map.put("principal", principal); + krb5.initialize(s, null, shared, map); + krb5.login(); + krb5.commit(); + m = GSSManager.getInstance(); + cred = Subject.doAs(s, new PrivilegedExceptionAction() { + @Override + public GSSCredential run() throws Exception { + System.err.println("Creating GSSCredential"); + return m.createCredential( + null, + GSSCredential.INDEFINITE_LIFETIME, + MyServerAuthenticator.this.scheme + .equalsIgnoreCase("Negotiate") ? + GSSUtil.GSS_SPNEGO_MECH_OID : + GSSUtil.GSS_KRB5_MECH_OID, + GSSCredential.ACCEPT_ONLY); + } + }); + } + + @Override + public Result authenticate(HttpExchange exch) { + // The GSContext is stored in an HttpContext attribute named + // "GSSContext" and is created at the first request. + GSSContext c = null; + String auth = exch.getRequestHeaders().getFirst(respHdr); + try { + c = (GSSContext)exch.getHttpContext() + .getAttributes().get("GSSContext"); + if (auth == null) { // First request + Headers map = exch.getResponseHeaders(); + map.set (reqHdr, scheme); // Challenge! + c = Subject.doAs(s, new PrivilegedExceptionAction() { + @Override + public GSSContext run() throws Exception { + return m.createContext(cred); + } + }); + // CBT is required for cbtURL + if (exch instanceof HttpsExchange sexch + && exch.getRequestURI().toString().equals("/cbt")) { + TlsChannelBinding b = TlsChannelBinding.create( + (X509Certificate) sexch.getSSLSession() + .getLocalCertificates()[0]); + c.setChannelBinding( + new TlsChannelBindingImpl(b.getData())); + } + exch.getHttpContext().getAttributes().put("GSSContext", c); + return new com.sun.net.httpserver.Authenticator.Retry(err); + } else { // Later requests + byte[] token = Base64.getMimeDecoder() + .decode(auth.split(" ")[1]); + token = c.acceptSecContext(token, 0, token.length); + Headers map = exch.getResponseHeaders(); + map.set (reqHdr, scheme + " " + Base64.getMimeEncoder() + .encodeToString(token).replaceAll("\\s", "")); + if (c.isEstablished()) { + return new com.sun.net.httpserver.Authenticator.Success( + new HttpPrincipal(c.getSrcName().toString(), "")); + } else { + return new com.sun.net.httpserver.Authenticator.Retry(err); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } +} diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/krb5/auto/IgnoreChannelBinding.java openjdk-17-17.0.4+8/test/jdk/sun/security/krb5/auto/IgnoreChannelBinding.java --- openjdk-17-17.0.3+7/test/jdk/sun/security/krb5/auto/IgnoreChannelBinding.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/krb5/auto/IgnoreChannelBinding.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. * 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 6851973 8194486 + * @bug 6851973 8194486 8279520 * @summary ignore incoming channel binding if acceptor does not set one * @library /test/lib * @run main jdk.test.lib.FileInstaller TestHosts TestHosts @@ -33,6 +33,7 @@ import java.net.InetAddress; import org.ietf.jgss.ChannelBinding; import org.ietf.jgss.GSSException; +import org.ietf.jgss.Oid; import sun.security.jgss.GSSUtil; public class IgnoreChannelBinding { @@ -41,33 +42,38 @@ throws Exception { new OneKDC(null).writeJAASConf(); + test(GSSUtil.GSS_KRB5_MECH_OID); + test(GSSUtil.GSS_SPNEGO_MECH_OID); + } + + static void test(Oid mech) throws Exception { Context c = Context.fromJAAS("client"); Context s = Context.fromJAAS("server"); // All silent - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); + s.startAsServer(mech); Context.handshake(c, s); // Initiator req, acceptor ignore - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); c.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), new byte[0] )); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(mech); Context.handshake(c, s); // Both req, and match - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); c.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), new byte[0] )); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(mech); s.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), @@ -76,13 +82,13 @@ Context.handshake(c, s); // Both req, NOT match - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); c.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), new byte[0] )); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(mech); s.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), @@ -96,8 +102,8 @@ } // Acceptor req, reject - c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); - s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(OneKDC.SERVER, mech); + s.startAsServer(mech); s.x().setChannelBinding(new ChannelBinding( InetAddress.getByName("client.rabbit.hole"), InetAddress.getByName("host.rabbit.hole"), diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java openjdk-17-17.0.4+8/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java --- openjdk-17-17.0.3+7/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,4 +1,5 @@ /* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Amazon.com, Inc. or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -21,7 +22,6 @@ * questions. */ -import java.math.BigInteger; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -86,7 +86,7 @@ private static void testKeySpec(KeyFactory factory, PrivateKey key, Class specClass) throws Exception { try { - KeySpec spec = factory.getKeySpec(key, RSAPrivateKeySpec.class); + KeySpec spec = factory.getKeySpec(key, specClass); if (testingSensitiveKeys) { throw new Exception("Able to retrieve spec from sensitive key"); } diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca2g1-chain.pem openjdk-17-17.0.4+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca2g1-chain.pem --- openjdk-17-17.0.3+7/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca2g1-chain.pem 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca2g1-chain.pem 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGGzCCBQOgAwIBAgIITJltLCqcD0gwDQYJKoZIhvcNAQELBQAwYjEcMBoGA1UE -AxMTQXBwbGUgSVNUIENBIDIgLSBHMTEgMB4GA1UECxMXQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkxEzARBgNVBAoTCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMB4XDTE5 -MDEwODIxMTcxNFoXDTIwMDgwODIxMjcwMFowgaoxSjBIBgNVBAMMQWFjdGl2ZS5n -ZW90cnVzdC1nbG9iYWwtY2EudGVzdC1wYWdlcy5jZXJ0aWZpY2F0ZW1hbmFnZXIu -YXBwbGUuY29tMSUwIwYDVQQLDBxtYW5hZ2VtZW50OmlkbXMuZ3JvdXAuODY0ODU5 -MRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMQswCQYD -VQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMCjFUrVHTEX -0aVU6x9LiGa6oVr9blaCsMFrLicPQguc43Vs/pN+g4jzRXsTSMe9XefezBQb6tzZ -SMRXVB4kWMr4K1BVgQDkXeyoh4KrXRkdEF9ZIJPNxwTmmYUOc5M6NOYwkLelYz+t -7n1iNIGylbjwU4qwauElk2alFVqYTEPDLzwvqVDb9jMAJ8MPSDjfUlXW0XD9oXZM -hC+8LU9JBgJ3YBdzRHa4WnrudUbWjspqaNfAYpVIX0cfCJKnMsKqaSKjS4pIRtWm -L6NlCTCoIMyOh+wmbWPPX24H2D3+ump5FA35fRYbVznmosl5n1AK34S9tD4XZ7lO -WZKfaFi1liMCAwEAAaOCAoowggKGMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU -2HqURHyQcJAWnt0XnAFEA4bWKikwfgYIKwYBBQUHAQEEcjBwMDQGCCsGAQUFBzAC -hihodHRwOi8vY2VydHMuYXBwbGUuY29tL2FwcGxlaXN0Y2EyZzEuZGVyMDgGCCsG -AQUFBzABhixodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDAzLWFwcGxlaXN0Y2Ey -ZzEwMTBMBgNVHREERTBDgkFhY3RpdmUuZ2VvdHJ1c3QtZ2xvYmFsLWNhLnRlc3Qt -cGFnZXMuY2VydGlmaWNhdGVtYW5hZ2VyLmFwcGxlLmNvbTCB/wYDVR0gBIH3MIH0 -MIHxBgoqhkiG92NkBQsEMIHiMIGkBggrBgEFBQcCAjCBlwyBlFJlbGlhbmNlIG9u -IHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5j -ZSBvZiBhbnkgYXBwbGljYWJsZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2Ug -YW5kL29yIGNlcnRpZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wOQYIKwYB -BQUHAgEWLWh0dHA6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5 -L3JwYTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwNwYDVR0fBDAwLjAs -oCqgKIYmaHR0cDovL2NybC5hcHBsZS5jb20vYXBwbGVpc3RjYTJnMS5jcmwwHQYD -VR0OBBYEFP0qkmFJhArI0MsfW0V+/wY9x4GSMA4GA1UdDwEB/wQEAwIFoDANBgkq -hkiG9w0BAQsFAAOCAQEATjT8M0bIq+mFc8k5cd4KDjCMBjYl/l3/8zKlWYGP+nl1 -KRogXcGRa3LcfpdJcqgMrx8e9Xohduvl8MBzwv671rYkppzZdsmZdLVorAdbL5GL -suhTjAS5yL3NBWNMRpeOgFsVr7YtPDEvo3CFsnzjg7THe0S6Y35oYukJtUzGUvSY -kC3ApBTdjj0vAeow+dbt+AHKnQiEnon4ToSFmtnkru08Uxe7uyHCQ2sLUg0EPYc9 -t9I8lviaHfK/mQoCzlme2O/H5Rher8dXCv8hVT1NKbsi28EpgpqcTLS+hn/Edc/q -4dPDoO1Ozs+ixRzFeMpA+JrnAyARb6qbSrAPBgtIbQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEQDCCAyigAwIBAgIDAjp0MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMTQwNjE2MTU0MjAyWhcNMjIwNTIwMTU0MjAyWjBiMRwwGgYDVQQD -ExNBcHBsZSBJU1QgQ0EgMiAtIEcxMSAwHgYDVQQLExdDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTETMBEGA1UEChMKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQk6EdR0MgFrILa+vD1bTox5jN896/ -6E3p4zaAB/xFG2p8RYauVtOkCX9hDWtdflJrfbTIOcT0Zzr3g84Zb4YvfkV+Rxxn -UsqVBV3iNlGFwNRngDVvFd0+/R3S/Y80UNjsdiq+49Pa5P3I6ygClhGXF2Ec6cRZ -O0LcMtEJHdqm0UOG/16yvIzPZtsBiwKulEjzOI/96jKoCOyGl1GUJD5JSZZT6Hmh -QIHpBbuTlVH84/18EUv3ngizFUkVB/nRN6CbSzL2tcTcatH8Cu324MUpoKiLcf4N -krz+VHAYCm3H7Qz7yS0Gw4yF/MuGXNY2jhKLCX/7GRo41fCUMHoPpozzAgMBAAGj -ggEdMIIBGTAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjAdBgNVHQ4E -FgQU2HqURHyQcJAWnt0XnAFEA4bWKikwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNV -HQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2cuc3ltY2IuY29t -L2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYS -aHR0cDovL2cuc3ltY2QuY29tMEwGA1UdIARFMEMwQQYKYIZIAYb4RQEHNjAzMDEG -CCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvY3Bz -MA0GCSqGSIb3DQEBCwUAA4IBAQAWR3NvhaJi4ecqdruJlUIml7xKrKxwUzo/MYM9 -PByrmuKxXRx2GqA8DHJXvtOeUODImdZY1wLqzg0pVHzN9cLGkClVo28UqAtCDTqY -bQZ4nvBqox0CCqIopI3CgUY+bWfa3j/+hQ5CKhLetbf7uBunlux3n+zUU5V6/wf0 -8goUwFFSsdaOUAsamVy8C8m97e34XsFW201+I6QRoSzUGwWa5BtS9nw4mQVLunKN -QolgBGYq9P1o12v3mUEo1mwkq+YlUy7Igpnioo8jvjCDsSeL+mh/AUnoxphrEC6Y -XorXykuxx8lYmtA225aV7LaB5PLNbxt5h0wQPInkTfpU3Kqm ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg -R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 -9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq -fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv -iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU -1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ -bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW -MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA -ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l -uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn -Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS -tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF -PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un -hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV -5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== ------END CERTIFICATE----- diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java openjdk-17-17.0.4+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java --- openjdk-17-17.0.3+7/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,15 +54,14 @@ // Each of the roots have a test certificate chain stored in a file // named "-chain.pem". private static String[] rootsToTest = new String[] { - "geotrustglobalca", "geotrustprimarycag2", "geotrustprimarycag3", + "geotrustprimarycag2", "geotrustprimarycag3", "geotrustuniversalca", "thawteprimaryrootca", "thawteprimaryrootcag2", "thawteprimaryrootcag3", "verisignclass3g3ca", "verisignclass3g4ca", "verisignclass3g5ca", "verisignuniversalrootca" }; // Each of the subCAs with a delayed distrust date have a test certificate // chain stored in a file named "-chain.pem". - private static String[] subCAsToTest = new String[] { - "appleistca2g1", "appleistca8g1" }; + private static String[] subCAsToTest = new String[]{"appleistca8g1"}; // A date that is after the restrictions take affect private static final Date APRIL_17_2019 = @@ -180,6 +179,11 @@ throw new Exception("chain should be invalid"); } } catch (CertificateException ce) { + // expired TLS certificates should not be treated as failure + if (expired(ce)) { + System.err.println("Test is N/A, chain is expired"); + return; + } if (valid) { throw new Exception("Unexpected exception, chain " + "should be valid", ce); @@ -187,6 +191,7 @@ if (ce instanceof ValidatorException) { ValidatorException ve = (ValidatorException)ce; if (ve.getErrorType() != ValidatorException.T_UNTRUSTED_CERT) { + ce.printStackTrace(System.err); throw new Exception("Unexpected exception: " + ce); } } else { @@ -195,6 +200,21 @@ } } + // check if a cause of exception is an expired cert + private static boolean expired(CertificateException ce) { + if (ce instanceof CertificateExpiredException) { + return true; + } + Throwable t = ce.getCause(); + while (t != null) { + if (t instanceof CertificateExpiredException) { + return true; + } + t = t.getCause(); + } + return false; + } + private static X509Certificate[] loadCertificateChain(String name) throws Exception { try (InputStream in = new FileInputStream(TEST_SRC + File.separator + diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustglobalca-chain.pem openjdk-17-17.0.4+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustglobalca-chain.pem --- openjdk-17-17.0.3+7/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustglobalca-chain.pem 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustglobalca-chain.pem 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIHBjCCBe6gAwIBAgIQanINWwJAuap0V7lFjnfUwTANBgkqhkiG9w0BAQsFADBE -MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMU -R2VvVHJ1c3QgU1NMIENBIC0gRzMwHhcNMTcwNTAzMDAwMDAwWhcNMjAwNTAyMjM1 -OTU5WjCBkTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNV -BAcMDU1vdW50YWluIFZpZXcxFzAVBgNVBAoMDkdlb1RydXN0LCBJbmMuMRgwFgYD -VQQLDA9Sb290IDEwIC0gVkFMSUQxIjAgBgNVBAMMGXZhbGlkLXJvb3QxMC5nZW90 -cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTegUYhAh0 -P7aF6jzk8dit4Vzddo3hM+J7Eak/+N1sqVUS2HpNd7VO50FrbEWKIRusv7QNtlpY -1Cgrla8M4RAhCB0wkkHXZ1Evz6E1AEFQqNSjyuRQxeEXl+xCL+MF+yAMhDRnHh+E -eSJ3ie0T66saOyaLM9fPpr3xomAQ/IRlP1atJ/Z8XbPo25HuxwzxiWFW+RjwVIfI -gxHz4Okwc1uImDUIDlEu9Uaqqb4jHhxU1EkKMmgEncpqwCROcZMujUkogfB49Z7+ -K17r6ARIrUuxqfNPrPwe+O88WgIeDSWffPM67UlvtomZOwuTNdv9OoCX1wUCLS7m -/gZ3rqqqeJvfAgMBAAGjggOkMIIDoDAkBgNVHREEHTAbghl2YWxpZC1yb290MTAu -Z2VvdHJ1c3QuY29tMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgWgMCsGA1UdHwQk -MCIwIKAeoByGGmh0dHA6Ly9nbi5zeW1jYi5jb20vZ24uY3JsMIGdBgNVHSAEgZUw -gZIwgY8GBmeBDAECAjCBhDA/BggrBgEFBQcCARYzaHR0cHM6Ly93d3cuZ2VvdHJ1 -c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5L2xlZ2FsMEEGCCsGAQUFBwICMDUM -M2h0dHBzOi8vd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeS9s -ZWdhbDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHwYDVR0jBBgwFoAU -0m/3lvSFP3I8MH0j2oV4m6N8WnwwVwYIKwYBBQUHAQEESzBJMB8GCCsGAQUFBzAB -hhNodHRwOi8vZ24uc3ltY2QuY29tMCYGCCsGAQUFBzAChhpodHRwOi8vZ24uc3lt -Y2IuY29tL2duLmNydDCCAfUGCisGAQQB1nkCBAIEggHlBIIB4QHfAHUA3esdK3oN -T6Ygi4GtgWhwfi6OnQHVXIiNPRHEzbbsvswAAAFbz9h5vQAABAMARjBEAiAx/C0U -5NdHxK4v2oHnstYksb1Vny8PcQkSvgpx9PsZEwIgNTOU70Zc5szG23xdbvtoH5lN -SAoVswiF5gFQS5MGu1sAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3c -EAAAAVvP2HnZAAAEAwBHMEUCIFGjB8r2H0VDwTUE/aY/Mv+M97sqAvEP1doOcHpg -0qyfAiEArw/S2F7OEcmKGUY1WRBuApfAx5d7hzrTSV/jZv95qJwAdgDuS723dc5g -uuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAVvP2HoDAAAEAwBHMEUCIQCH6MFZ -tZF3Cqukt3/69fkU0Y5ePXXx8+xkOXRsIG3EGgIgSmCBWrnmPiiGA3x5QP8I8m4r -Uee0y7s4NQNwjMgHrjwAdgC8eOHfxfY8aEZJM02hD6FfCXlpIAnAgbTz9pF/Ptm4 -pQAAAVvP2HqcAAAEAwBHMEUCIA8e2kAVYYuQCtn4PqK98BuHnLm9rC40DboFLCle -SmQsAiEApbCJR05hr9VkNWmjaaUUGGZdVyUu9XX504LHVWyXZDUwDQYJKoZIhvcN -AQELBQADggEBAEtfBfZ2y5uTohvW3h00Kcuop6Nq7Y59GU3MeizPKtx48DB8qHyd -y5bLFwXzsGA1WkwpKzPbROsTGcAAXJHh03bj24AemUr/J/eQcjkfSoNBdHDpiSsk -VZkQK2fGJDiYJ/r9mxKZcgd2pyN3l2OtVtNMv2dnFGF35UkkeqO3jqImwbypAmRX -HdQV9dvW2YDRjzkebNNey6UwY9+YTSzr4da2hcaMHrj588Eqa4DDgNcY9QnE2RzN -giArA+4RlM4AZ3jC2A756I67hrlvH+lhumHLp06hGfMiQJF1aaauFVSa36HKc3C/ -ty+sLdJbemEJLAr8uNXggFD+U8TKw1S4LSw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIETzCCAzegAwIBAgIDAjpvMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMTMxMTA1MjEzNjUwWhcNMjIwNTIwMjEzNjUwWjBEMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg -U1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjvn4K -hqPPa209K6GXrUkkTdd3uTR5CKWeop7eRxKSPX7qGYax6E89X/fQp3eaWx8KA7UZ -U9ulIZRpY51qTJEMEEe+EfpshiW3qwRoQjgJZfAU2hme+msLq2LvjafvY3AjqK+B -89FuiGdT7BKkKXWKp/JXPaKDmJfyCn3U50NuMHhiIllZuHEnRaoPZsZVP/oyFysx -j0ag+mkUfJ2fWuLrM04QprPtd2PYw5703d95mnrU7t7dmszDt6ldzBE6B7tvl6QB -I0eVH6N3+liSxsfQvc+TGEK3fveeZerVO8rtrMVwof7UEJrwEgRErBpbeFBFV0xv -vYDLgVwts7x2oR5lAgMBAAGjggFKMIIBRjAfBgNVHSMEGDAWgBTAephojYn7qwVk -DBF9qn1luMrMTjAdBgNVHQ4EFgQU0m/3lvSFP3I8MH0j2oV4m6N8WnwwEgYDVR0T -AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNgYDVR0fBC8wLTAroCmgJ4Yl -aHR0cDovL2cxLnN5bWNiLmNvbS9jcmxzL2d0Z2xvYmFsLmNybDAvBggrBgEFBQcB -AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9nMi5zeW1jYi5jb20wTAYDVR0gBEUw -QzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1 -c3QuY29tL3Jlc291cmNlcy9jcHMwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMTEVN5 -bWFudGVjUEtJLTEtNTM5MA0GCSqGSIb3DQEBCwUAA4IBAQCg1Pcs+3QLf2TxzUNq -n2JTHAJ8mJCi7k9o1CAacxI+d7NQ63K87oi+fxfqd4+DYZVPhKHLMk9sIb7SaZZ9 -Y73cK6gf0BOEcP72NZWJ+aZ3sEbIu7cT9clgadZM/tKO79NgwYCA4ef7i28heUrg -3Kkbwbf7w0lZXLV3B0TUl/xJAIlvBk4BcBmsLxHA4uYPL4ZLjXvDuacu9PGsFj45 -SVGeF0tPEDpbpaiSb/361gsDTUdWVxnzy2v189bPsPX1oxHSIFMTNDcFLENaY9+N -QNaFHlHpURceA1bJ8TCt55sRornQMYGbaLHZ6PPmlH7HrhMvh+3QJbBo+d4IWvMp -zNSS ------END CERTIFICATE----- diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/util/DerInputBuffer/PaddedBitString.java openjdk-17-17.0.4+8/test/jdk/sun/security/util/DerInputBuffer/PaddedBitString.java --- openjdk-17-17.0.3+7/test/jdk/sun/security/util/DerInputBuffer/PaddedBitString.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/util/DerInputBuffer/PaddedBitString.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * 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,52 +26,82 @@ * @bug 4511556 * @summary Verify BitString value containing padding bits is accepted. * @modules java.base/sun.security.util + * @library /test/lib */ - import java.io.*; -import java.util.Arrays; import java.math.BigInteger; +import java.util.Arrays; +import java.util.HexFormat; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.security.util.BitArray; import sun.security.util.DerInputStream; public class PaddedBitString { // Relaxed the BitString parsing routine to accept bit strings - // with padding bits, ex. treat DER_BITSTRING_PAD6 as the same - // bit string as DER_BITSTRING_NOPAD. + // with padding bits, ex. treat DER_BITSTRING_PAD6_b as the same + // bit string as DER_BITSTRING_PAD6_0/DER_BITSTRING_NOPAD. // Note: // 1. the number of padding bits has to be in [0...7] // 2. value of the padding bits is ignored - // bit string (01011101 11000000) - // With 6 padding bits (01011101 11001011) - private final static byte[] DER_BITSTRING_PAD6 = { 3, 3, 6, - (byte)0x5d, (byte)0xcb }; - // With no padding bits private final static byte[] DER_BITSTRING_NOPAD = { 3, 3, 0, (byte)0x5d, (byte)0xc0 }; + // With 6 zero padding bits (01011101 11000000) + private final static byte[] DER_BITSTRING_PAD6_0 = { 3, 3, 6, + (byte)0x5d, (byte)0xc0 }; - public static void main(String args[]) throws Exception { - byte[] ba0, ba1; - try { - DerInputStream derin = new DerInputStream(DER_BITSTRING_PAD6); - ba1 = derin.getBitString(); - } catch( IOException e ) { - e.printStackTrace(); - throw new Exception("Unable to parse BitString with 6 padding bits"); - } + // With 6 nonzero padding bits (01011101 11001011) + private final static byte[] DER_BITSTRING_PAD6_b = { 3, 3, 6, + (byte)0x5d, (byte)0xcb }; - try { - DerInputStream derin = new DerInputStream(DER_BITSTRING_NOPAD); - ba0 = derin.getBitString(); - } catch( IOException e ) { - e.printStackTrace(); - throw new Exception("Unable to parse BitString with no padding"); - } + // With 8 padding bits + private final static byte[] DER_BITSTRING_PAD8_0 = { 3, 3, 8, + (byte)0x5d, (byte)0xc0 }; + + private final static byte[] BITS = { (byte)0x5d, (byte)0xc0 }; + + static enum Type { + BIT_STRING, + UNALIGNED_BIT_STRING; + } + + public static void main(String args[]) throws Exception { + test(DER_BITSTRING_NOPAD, new BitArray(16, BITS)); + test(DER_BITSTRING_PAD6_0, new BitArray(10, BITS)); + test(DER_BITSTRING_PAD6_b, new BitArray(10, BITS)); + test(DER_BITSTRING_PAD8_0, null); + System.out.println("Tests Passed"); + } - if (Arrays.equals(ba1, ba0) == false ) { - throw new Exception("BitString comparison check failed"); + private static void test(byte[] in, BitArray ans) throws IOException { + System.out.println("Testing " + + HexFormat.of().withUpperCase().formatHex(in)); + for (Type t : Type.values()) { + DerInputStream derin = new DerInputStream(in); + boolean shouldPass = (ans != null); + switch (t) { + case BIT_STRING: + if (shouldPass) { + Asserts.assertTrue(Arrays.equals(ans.toByteArray(), + derin.getBitString())); + } else { + Utils.runAndCheckException(() -> derin.getBitString(), + IOException.class); + } + break; + case UNALIGNED_BIT_STRING: + if (shouldPass) { + Asserts.assertEQ(ans, derin.getUnalignedBitString()); + } else { + Utils.runAndCheckException(() -> + derin.getUnalignedBitString(), IOException.class); + } + break; + } } } } diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/util/RegisteredDomain/ParseNames.java openjdk-17-17.0.4+8/test/jdk/sun/security/util/RegisteredDomain/ParseNames.java --- openjdk-17-17.0.3+7/test/jdk/sun/security/util/RegisteredDomain/ParseNames.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/util/RegisteredDomain/ParseNames.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * 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 8228969 8244087 + * @bug 8228969 8244087 8255266 * @modules java.base/sun.security.util * @summary unit test for RegisteredDomain */ diff -Nru openjdk-17-17.0.3+7/test/jdk/sun/security/util/RegisteredDomain/tests.dat openjdk-17-17.0.4+8/test/jdk/sun/security/util/RegisteredDomain/tests.dat --- openjdk-17-17.0.3+7/test/jdk/sun/security/util/RegisteredDomain/tests.dat 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/sun/security/util/RegisteredDomain/tests.dat 2022-07-14 08:05:38.000000000 +0000 @@ -56,6 +56,11 @@ site.biz biz site.biz w.site.biz biz site.biz +# br +br br null +dev.br dev.br null +x.dev.br dev.br x.dev.br + # cn (unicode) # foo.mil.cn mil.cn foo.mil.cn diff -Nru openjdk-17-17.0.3+7/test/jdk/tools/jar/JarEntryTime.java openjdk-17-17.0.4+8/test/jdk/tools/jar/JarEntryTime.java --- openjdk-17-17.0.3+7/test/jdk/tools/jar/JarEntryTime.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/tools/jar/JarEntryTime.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. * 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 4225317 6969651 + * @bug 4225317 6969651 8277422 * @modules jdk.jartool * @summary Check extracted files have date as per those in the .jar file */ @@ -31,6 +31,7 @@ import java.io.File; import java.io.PrintWriter; import java.nio.file.attribute.FileTime; +import java.time.ZoneId; import java.util.Date; import java.util.TimeZone; import java.util.spi.ToolProvider; @@ -93,6 +94,14 @@ jarFile.delete(); testFile.delete(); + var date = new Date(); + var defZone = ZoneId.systemDefault(); + if (defZone.getRules().getTransition( + date.toInstant().atZone(defZone).toLocalDateTime()) != null) { + System.out.println("At the offset transition. JarEntryTime test skipped."); + return; + } + /* Create a directory structure * outer/ * inner/ diff -Nru openjdk-17-17.0.3+7/test/jdk/tools/launcher/FXLauncherTest.java openjdk-17-17.0.4+8/test/jdk/tools/launcher/FXLauncherTest.java --- openjdk-17-17.0.3+7/test/jdk/tools/launcher/FXLauncherTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/tools/launcher/FXLauncherTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -360,6 +360,10 @@ */ @Test static void testMissingMC() throws Exception { + if (!isEnglishLocale()) { + return; + } + String testname = "testMissingMC"; testcount++; line(); diff -Nru openjdk-17-17.0.3+7/test/jdk/tools/launcher/SourceMode.java openjdk-17-17.0.4+8/test/jdk/tools/launcher/SourceMode.java --- openjdk-17-17.0.3+7/test/jdk/tools/launcher/SourceMode.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jdk/tools/launcher/SourceMode.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,6 +200,10 @@ // java --add-exports=... Export.java --help @Test void testAddExports() throws IOException { + if (!isEnglishLocale()) { + return; + } + starting("testAddExports"); Path exportJava = Paths.get("Export.java"); createFile(exportJava, List.of( @@ -254,6 +258,10 @@ // java --source N -cp ... HelloWorld @Test void testSourceClasspath() throws IOException { + if (!isEnglishLocale()) { + return; + } + starting("testSourceClasspath"); Path base = Files.createDirectories(Paths.get("testSourceClasspath")); Path src = Files.createDirectories(base.resolve("src")); diff -Nru openjdk-17-17.0.3+7/test/jtreg-ext/requires/VMProps.java openjdk-17-17.0.4+8/test/jtreg-ext/requires/VMProps.java --- openjdk-17-17.0.3+7/test/jtreg-ext/requires/VMProps.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/jtreg-ext/requires/VMProps.java 2022-07-14 08:05:38.000000000 +0000 @@ -102,6 +102,7 @@ // vm.hasJFR is "true" if JFR is included in the build of the VM and // so tests can be executed. map.put("vm.hasJFR", this::vmHasJFR); + map.put("vm.hasDTrace", this::vmHasDTrace); map.put("vm.jvmti", this::vmHasJVMTI); map.put("vm.cpu.features", this::cpuFeatures); map.put("vm.pageSize", this::vmPageSize); @@ -340,6 +341,13 @@ } /** + * @return "true" if the VM is compiled with DTrace + */ + protected String vmHasDTrace() { + return "" + WB.isDTraceIncluded(); + } + + /** * @return true if compiler in use supports RTM and false otherwise. */ protected String vmRTMCompiler() { diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testDocFileDir/TestDocFileDir.java openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testDocFileDir/TestDocFileDir.java --- openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testDocFileDir/TestDocFileDir.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testDocFileDir/TestDocFileDir.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * 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,13 +28,14 @@ * get overwritten when the sourcepath is equal to the destination * directory. * Also test that -docfilessubdirs and -excludedocfilessubdir both work. - * @library ../../lib + * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool - * @build javadoc.tester.* + * @build toolbox.ToolBox javadoc.tester.* * @run main TestDocFileDir */ import javadoc.tester.JavadocTester; +import toolbox.ToolBox; public class TestDocFileDir extends JavadocTester { @@ -43,10 +44,12 @@ tester.runTests(); } + ToolBox tb = new ToolBox(); + // Output dir = "", Input dir = "" @Test public void test1() { - copyDir(testSrc("pkg"), "."); + tb.copyDir(testSrc("pkg"), "pkg"); setOutputDirectoryCheck(DirectoryCheck.NO_HTML_FILES); javadoc("pkg/C.java"); checkExit(Exit.OK); @@ -58,7 +61,7 @@ @Test public void test2() { String outdir = "out2"; - copyDir(testSrc("pkg"), outdir); + tb.copyDir(testSrc("pkg"), outdir + "/pkg"); setOutputDirectoryCheck(DirectoryCheck.NO_HTML_FILES); javadoc("-d", outdir, "-sourcepath", "blah" + PS + outdir + PS + "blah", diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testMetadata/TestMetadata.java openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testMetadata/TestMetadata.java --- openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testMetadata/TestMetadata.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testMetadata/TestMetadata.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,9 +165,8 @@ ); void checkBodyClasses() throws IOException { - Path outputDirPath = outputDir.toPath(); - for (Path p : tb.findFiles(".html", outputDirPath)) { - checkBodyClass(outputDirPath.relativize(p)); + for (Path p : tb.findFiles(".html", outputDir)) { + checkBodyClass(outputDir.relativize(p)); } } @@ -231,9 +230,8 @@ ); void checkMetadata() throws IOException { - Path outputDirPath = outputDir.toPath(); - for (Path p : tb.findFiles(".html", outputDirPath)) { - checkMetadata(outputDirPath.relativize(p)); + for (Path p : tb.findFiles(".html", outputDir)) { + checkMetadata(outputDir.relativize(p)); } } diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testRelativeLinks/TestRelativeLinks.java openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testRelativeLinks/TestRelativeLinks.java --- openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testRelativeLinks/TestRelativeLinks.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testRelativeLinks/TestRelativeLinks.java 2022-07-14 08:05:38.000000000 +0000 @@ -35,6 +35,9 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; import javadoc.tester.JavadocTester; @@ -200,9 +203,9 @@ } private void touch(String file) { - File f = new File(outputDir, file); + Path f = outputDir.resolve(file); out.println("touch " + f); - try (FileOutputStream fos = new FileOutputStream(f)) { + try (OutputStream fos = Files.newOutputStream(f)) { } catch (IOException e) { checking("Touch file"); failed("Error creating file: " + e); diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testSearchScript/TestSearchScript.java openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testSearchScript/TestSearchScript.java --- openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testSearchScript/TestSearchScript.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testSearchScript/TestSearchScript.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * 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,10 +41,9 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import jtreg.SkippedException; @@ -71,9 +70,9 @@ // see https://github.com/graalvm/graaljs/blob/master/docs/user/ScriptEngine.md Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); bindings.put("polyglot.js.nashorn-compat", true); - engine.eval(new BufferedReader(new FileReader(new File(testSrc, "javadoc-search.js")))); + engine.eval(Files.newBufferedReader(Path.of(testSrc).resolve("javadoc-search.js"))); Invocable inv = (Invocable) engine; - inv.invokeFunction("loadIndexFiles", outputDir.getAbsolutePath()); + inv.invokeFunction("loadIndexFiles", outputDir.toAbsolutePath().toString()); return inv; } diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java --- openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java 2022-07-14 08:05:38.000000000 +0000 @@ -206,7 +206,7 @@ checking("Check lists"); ListChecker c = new ListChecker(out, this::readFile); try { - c.checkDirectory(outputDir.toPath()); + c.checkDirectory(outputDir); c.report(); int errors = c.getErrorCount(); if (errors == 0) { diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java --- openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java 2022-07-14 08:05:38.000000000 +0000 @@ -381,7 +381,7 @@ checking("Check CSS class names"); CSSClassChecker c = new CSSClassChecker(out, this::readFile, styles); try { - c.checkDirectory(outputDir.toPath()); + c.checkDirectory(outputDir); c.report(); int errors = c.getErrorCount(); if (errors == 0) { diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java --- openjdk-17-17.0.3+7/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java 2022-07-14 08:05:38.000000000 +0000 @@ -25,10 +25,7 @@ import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; @@ -41,13 +38,18 @@ import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.EnumMap; import java.util.HashMap; import java.util.List; @@ -157,7 +159,7 @@ } /** The output directory used in the most recent call of javadoc. */ - protected File outputDir; + protected Path outputDir; /** The output charset used in the most recent call of javadoc. */ protected Charset charset = Charset.defaultCharset(); @@ -169,7 +171,7 @@ private final Map outputMap = new EnumMap<>(Output.class); /** A cache of file content, to avoid reading files unnecessarily. */ - private final Map> fileContentCache = new HashMap<>(); + private final Map> fileContentCache = new HashMap<>(); /** The charset used for files in the fileContentCache. */ private Charset fileContentCacheCharset = null; @@ -185,7 +187,7 @@ * @return the full path of the specified file */ public static String testSrc(String path) { - return new File(testSrc, path).getPath(); + return Path.of(testSrc).resolve(path).toString(); } /** @@ -195,35 +197,40 @@ /** * Check that the directory is empty. */ - EMPTY((file, name) -> true), + EMPTY(p -> true), /** * Check that the directory does not contain any HTML files, * such as may have been generated by a prior run of javadoc * using this directory. * For now, the check is only performed on the top level directory. */ - NO_HTML_FILES((file, name) -> name.endsWith(".html")), + NO_HTML_FILES(p -> p.getFileName().toString().endsWith(".html")), /** * No check is performed on the directory contents. */ - NONE(null) { @Override void check(File dir) { } }; + NONE(null) { @Override void check(Path dir) { } }; /** The filter used to detect that files should not be present. */ - FilenameFilter filter; + DirectoryStream.Filter filter; - DirectoryCheck(FilenameFilter f) { + DirectoryCheck(DirectoryStream.Filter f) { filter = f; } - void check(File dir) { - if (dir.isDirectory()) { - String[] contents = dir.list(filter); - if (contents == null) - throw new Error("cannot list directory: " + dir); - if (contents.length > 0) { - System.err.println("Found extraneous files in dir:" + dir.getAbsolutePath()); - for (String x : contents) { - System.err.println(x); + void check(Path dir) { + if (Files.isDirectory(dir)) { + List contents = new ArrayList<>(); + try (var ds = Files.newDirectoryStream(dir, filter)) { + for (Path p : ds) { + contents.add(p); + } + } catch (IOException e) { + throw new Error("cannot list directory: " + dir + "; " + e, e); + } + if (!contents.isEmpty()) { + System.err.println("Found extraneous files in dir:" + dir.toAbsolutePath()); + for (Path p : contents) { + System.err.println(p); } throw new Error("directory has unexpected content: " + dir); } @@ -316,13 +323,13 @@ out.println("Running javadoc (run "+ javadocRunNum + ")..."); } - outputDir = new File("."); + outputDir = Path.of("."); String charsetArg = null; String docencodingArg = null; String encodingArg = null; for (int i = 0; i < args.length - 2; i++) { switch (args[i]) { - case "-d" -> outputDir = new File(args[++i]); + case "-d" -> outputDir = Path.of(args[++i]); case "-charset" -> charsetArg = args[++i]; case "-docencoding" -> docencodingArg = args[++i]; case "-encoding" -> encodingArg = args[++i]; @@ -377,7 +384,7 @@ } }); - if (exitCode == Exit.OK.code && outputDir.exists()) { + if (exitCode == Exit.OK.code && Files.exists(outputDir)) { if (automaticCheckLinks) { checkLinks(); } @@ -502,8 +509,8 @@ public void checkOutput(String path, boolean expectedFound, String... strings) { // Read contents of file try { - String fileString = readFile(outputDir, path); - checkOutput(new File(outputDir, path).getPath(), fileString, expectedFound, strings); + String fileString = readFile(outputDir, Path.of(path)); + checkOutput(outputDir.resolve(path).toString(), fileString, expectedFound, strings); } catch (Error e) { checking("Read file"); failed("Error reading file: " + e); @@ -594,7 +601,7 @@ checking("Check accessibility"); A11yChecker c = new A11yChecker(out, this::readFile); try { - c.checkDirectory(outputDir.toPath()); + c.checkDirectory(outputDir); c.report(); int errors = c.getErrorCount(); if (errors == 0) { @@ -616,7 +623,7 @@ checking("Check links"); LinkChecker c = new LinkChecker(out, this::readFile); try { - c.checkDirectory(outputDir.toPath()); + c.checkDirectory(outputDir); c.report(); int errors = c.getErrorCount(); if (errors == 0) { @@ -641,8 +648,8 @@ ShowHeadings s = new ShowHeadings(out, this::readFile); for (String p : paths) { try { - File f = new File(outputDir, p); - s.checkFiles(List.of(f.toPath()), false, Collections.emptySet()); + Path f = outputDir.resolve(p); + s.checkFiles(List.of(f), false, Collections.emptySet()); } catch (IOException e) { checking("Read file"); failed("Error reading file: " + e); @@ -691,8 +698,8 @@ for (String path: paths) { // log.logCheckFile(path, expectedFound); checking("checkFile"); - File file = new File(outputDir, path); - boolean isFound = file.exists(); + Path file = outputDir.resolve(path); + boolean isFound = Files.exists(file); if (isFound == expectedFound) { passed(file, "file " + (isFound ? "found:" : "not found:") + "\n"); } else { @@ -708,7 +715,7 @@ * @param strings the strings whose order to check */ public void checkOrder(String path, String... strings) { - File file = new File(outputDir, path); + Path file = outputDir.resolve(path); String fileString = readOutputFile(path); int prevIndex = -1; for (String s : strings) { @@ -736,7 +743,7 @@ * @param strings ensure each are unique */ public void checkUnique(String path, String... strings) { - File file = new File(outputDir, path); + Path file = outputDir.resolve(path); String fileString = readOutputFile(path); for (String s : strings) { int currentIndex = fileString.indexOf(s); @@ -762,86 +769,41 @@ * @param files the set of files to be compared */ public void diff(String baseDir1, String baseDir2, String... files) { - File bd1 = new File(baseDir1); - File bd2 = new File(baseDir2); + Path bd1 = Path.of(baseDir1); + Path bd2 = Path.of(baseDir2); for (String file : files) { - diff(bd1, bd2, file); + diff(bd1, bd2, Path.of(file)); } } /** - * Copies a directory from one place to another. - * - * @param targetDir the directory to copy. - * @param destDir the destination to copy the directory to. - */ - // TODO: convert to using java.nio.Files.walkFileTree - public void copyDir(String targetDir, String destDir) { - try { - File targetDirObj = new File(targetDir); - File destDirParentObj = new File(destDir); - File destDirObj = new File(destDirParentObj, targetDirObj.getName()); - if (! destDirParentObj.exists()) { - destDirParentObj.mkdir(); - } - if (! destDirObj.exists()) { - destDirObj.mkdir(); - } - String[] files = targetDirObj.list(); - for (String file : files) { - File srcFile = new File(targetDirObj, file); - File destFile = new File(destDirObj, file); - if (srcFile.isFile()) { - out.println("Copying " + srcFile + " to " + destFile); - copyFile(destFile, srcFile); - } else if(srcFile.isDirectory()) { - copyDir(srcFile.getAbsolutePath(), destDirObj.getAbsolutePath()); - } - } - } catch (IOException exc) { - throw new Error("Could not copy " + targetDir + " to " + destDir); - } - } - - /** - * Copies a file. - * - * @param destfile the destination file - * @param srcfile the source file - * @throws IOException - */ - public void copyFile(File destfile, File srcfile) throws IOException { - Files.copy(srcfile.toPath(), destfile.toPath()); - } - - /** * Read a file from the output directory. * * @param fileName the name of the file to read * @return the file in string format */ public String readOutputFile(String fileName) throws Error { - return readFile(outputDir, fileName); + return readFile(outputDir, Path.of(fileName)); } protected String readFile(String fileName) throws Error { - return readFile(outputDir, fileName); + return readFile(outputDir, Path.of(fileName)); } protected String readFile(String baseDir, String fileName) throws Error { - return readFile(new File(baseDir), fileName); + return readFile(Path.of(baseDir), Path.of(fileName)); } protected String readFile(Path file) { - File baseDir; - if (file.startsWith(outputDir.toPath())) { + Path baseDir; + if (file.startsWith(outputDir)) { baseDir = outputDir; } else if (file.startsWith(currDir)) { - baseDir = currDir.toFile(); + baseDir = currDir; } else { - baseDir = file.getParent().toFile(); + baseDir = file.getParent(); } - String fileName = baseDir.toPath().relativize(file).toString(); + Path fileName = baseDir.relativize(file); return readFile(baseDir, fileName); } @@ -852,20 +814,20 @@ * @param fileName the name of the file to read * @return the file in string format */ - private String readFile(File baseDir, String fileName) throws Error { + private String readFile(Path baseDir, Path fileName) throws Error { if (!Objects.equals(fileContentCacheCharset, charset)) { fileContentCache.clear(); fileContentCacheCharset = charset; } try { - File file = new File(baseDir, fileName); + Path file = baseDir.resolve(fileName); SoftReference ref = fileContentCache.get(file); String content = (ref == null) ? null : ref.get(); if (content != null) return content; // charset defaults to a value inferred from latest javadoc run - content = new String(Files.readAllBytes(file.toPath()), charset); + content = new String(Files.readAllBytes(file), charset); fileContentCache.put(file, new SoftReference<>(content)); return content; } catch (FileNotFoundException e) { @@ -897,7 +859,7 @@ * @param file the file that was the focus of the check * @param message a short description of the outcome */ - protected void passed(File file, String message) { + protected void passed(Path file, String message) { passed(file + ": " + message); } @@ -922,7 +884,7 @@ * @param file the file that was the focus of the check * @param message a short description of the outcome */ - protected void failed(File file, String message) { + protected void failed(Path file, String message) { failed(file + ": " + message); } @@ -1002,10 +964,10 @@ * @param baseDir2 the directory in which to locate the second file * @param file the file to compare in the two base directories */ - private void diff(File baseDir1, File baseDir2, String file) { + private void diff(Path baseDir1, Path baseDir2, Path file) { String file1Contents = readFile(baseDir1, file); String file2Contents = readFile(baseDir2, file); - checking("diff " + new File(baseDir1, file) + ", " + new File(baseDir2, file)); + checking("diff " + baseDir1.resolve(file) + ", " + baseDir2.resolve(file)); if (file1Contents.trim().compareTo(file2Contents.trim()) == 0) { passed("files are equal"); } else { @@ -1068,44 +1030,46 @@ private static final int SUFFIX = 20; private static final int MAX = PREFIX + SUFFIX; List tests = new ArrayList<>(); - String outDir; - String rootDir = rootDir(); + Path outDir; + Path rootDir = rootDir(); - static String rootDir() { - File f = new File(".").getAbsoluteFile(); - while (!new File(f, ".hg").exists()) - f = f.getParentFile(); - return f.getPath(); + static Path rootDir() { + Path f = Path.of(".").toAbsolutePath(); + while (f != null && !Files.exists(f.resolve(".git"))) + f = f.getParent(); + return f; } - void setOutDir(File outDir) { - this.outDir = outDir.getPath(); + void setOutDir(Path outDir) { + this.outDir = outDir; } void logCheckFile(String file, boolean positive) { // Strip the outdir because that will typically not be the same - if (file.startsWith(outDir + "/")) - file = file.substring(outDir.length() + 1); - tests.add(file + " " + positive); + Path p = Path.of(file); + if (p.startsWith(outDir)) + p = p.relativize(outDir); + tests.add(p + " " + positive); } void logCheckOutput(String file, boolean positive, String text) { // Compress the string to be displayed in the log file - String simpleText = text.replaceAll("\\s+", " ").replace(rootDir, "[ROOT]"); + String simpleText = text.replaceAll("\\s+", " ").replace(rootDir.toString(), "[ROOT]"); if (simpleText.length() > MAX) simpleText = simpleText.substring(0, PREFIX) + "..." + simpleText.substring(simpleText.length() - SUFFIX); // Strip the outdir because that will typically not be the same - if (file.startsWith(outDir + "/")) - file = file.substring(outDir.length() + 1); + Path p = Path.of(file); + if (p.startsWith(outDir)) + p = p.relativize(outDir); // The use of text.hashCode ensure that all of "text" is taken into account - tests.add(file + " " + positive + " " + text.hashCode() + " " + simpleText); + tests.add(p + " " + positive + " " + text.hashCode() + " " + simpleText); } void write() { // sort the log entries because the subtests may not be executed in the same order - tests.sort((a, b) -> a.compareTo(b)); - try (BufferedWriter bw = new BufferedWriter(new FileWriter("tester.log"))) { + tests.sort(Comparator.naturalOrder()); + try (var bw = Files.newBufferedWriter(Path.of("tester.log"))) { for (String t: tests) { bw.write(t); bw.newLine(); @@ -1116,6 +1080,4 @@ } } - // Support classes for checkLinks - } \ No newline at end of file diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/jshell/ToolBasicTest.java openjdk-17-17.0.4+8/test/langtools/jdk/jshell/ToolBasicTest.java --- openjdk-17-17.0.3+7/test/langtools/jdk/jshell/ToolBasicTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/jshell/ToolBasicTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -553,7 +553,7 @@ } public void testOpenResource() { - test( + test(new String[]{"-R", "-Duser.language=en", "-R", "-Duser.country=US"}, (a) -> assertCommand(a, "/open PRINTING", ""), (a) -> assertCommandOutputContains(a, "/list", "void println", "System.out.printf"), diff -Nru openjdk-17-17.0.3+7/test/langtools/jdk/jshell/ToolSimpleTest.java openjdk-17-17.0.4+8/test/langtools/jdk/jshell/ToolSimpleTest.java --- openjdk-17-17.0.3+7/test/langtools/jdk/jshell/ToolSimpleTest.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/jdk/jshell/ToolSimpleTest.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -744,7 +744,8 @@ @Test public void testCompoundStart() { - test(new String[]{"--startup", "DEFAULT", "--startup", "PRINTING"}, + test(new String[]{"-R", "-Duser.language=en", "-R", "-Duser.country=US", + "--startup", "DEFAULT", "--startup", "PRINTING"}, (a) -> assertCommand(a, "printf(\"%4.2f\", Math.PI)", "", "", null, "3.14", "") ); diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest1.java openjdk-17-17.0.4+8/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest1.java --- openjdk-17-17.0.3+7/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest1.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest1.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * 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 8003639 * @summary convert lambda testng tests to jtreg and add them - * @run testng LambdaTranslationTest1 + * @run testng/othervm -Duser.language=en -Duser.country=US LambdaTranslationTest1 */ import org.testng.annotations.Test; diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest2.java openjdk-17-17.0.4+8/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest2.java --- openjdk-17-17.0.3+7/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest2.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/javac/lambda/lambdaExecution/LambdaTranslationTest2.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * 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 8003639 * @summary convert lambda testng tests to jtreg and add them - * @run testng LambdaTranslationTest2 + * @run testng/othervm -Duser.language=en -Duser.country=US LambdaTranslationTest2 */ import org.testng.annotations.Test; diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java openjdk-17-17.0.4+8/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java --- openjdk-17-17.0.3+7/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java 2022-07-14 08:05:38.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 +27,10 @@ * 8235458 * @summary javac shouldn't fail when an annotation processor report a message about an annotation on a module * javac should process annotated module when imports statement are present + * @library /tools/lib * @modules jdk.compiler + * @build toolbox.ToolBox + * @run main ReportOnImportedModuleAnnotation */ import java.io.PrintWriter; @@ -41,6 +44,8 @@ import javax.tools.StandardLocation; import javax.tools.ToolProvider; +import toolbox.ToolBox; + public class ReportOnImportedModuleAnnotation { public static void main(String[] args) throws Exception { @@ -49,6 +54,9 @@ final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + // Clean any existing files in output directory + (new ToolBox()).cleanDirectory(testOutputPath); + // Compile annotation and processor modules StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); fileManager.setLocationFromPaths(StandardLocation.MODULE_SOURCE_PATH, List.of(testBasePath.resolve("mods-src1/"))); diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/MultiVersionError.java openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/MultiVersionError.java --- openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/MultiVersionError.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/MultiVersionError.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8277165 + * @library ../lib + * @build CompilerUtils + * @run testng MultiVersionError + * @summary Tests multiple versions of the same class file + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; +import java.util.spi.ToolProvider; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; + +public class MultiVersionError { + private static final String TEST_SRC = System.getProperty("test.src"); + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + + private static final Path MODS_DIR = Paths.get("mods"); + + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar").orElseThrow(); + private static final Set modules = Set.of("m1", "m2"); + + /** + * Compiles classes used by the test + */ + @BeforeTest + public void compileAll() throws Exception { + CompilerUtils.cleanDir(MODS_DIR); + modules.forEach(mn -> + assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn))); + + // create a modular multi-release m1.jar + Path m1 = MODS_DIR.resolve("m1"); + Path m2 = MODS_DIR.resolve("m2"); + jar("cf", "m1.jar", "-C", m1.toString(), "p/Test.class", + "--release", "9", "-C", m1.toString(), "module-info.class", + "--release", "11", "-C", m1.toString(), "p/internal/P.class"); + jar("cf", "m2.jar", "-C", m2.toString(), "q/Q.class", + "--release", "10", "-C", m2.toString(), "module-info.class"); + + // package private p/internal/P.class in m1 instead + jar("cf", "m3.jar", "-C", m2.toString(), "q/Q.class", + "--release", "12", "-C", m2.toString(), "module-info.class", + "-C", m1.toString(), "p/internal/P.class"); + } + + /* + * multiple module-info.class from different versions should be excluded + * from multiple version check. + */ + @Test + public void noMultiVersionClass() { + // skip parsing p.internal.P to workaround JDK-8277681 + JdepsRunner jdepsRunner = new JdepsRunner("--print-module-deps", "--multi-release", "10", + "--ignore-missing-deps", + "--module-path", "m1.jar", "m2.jar"); + int rc = jdepsRunner.run(true); + assertTrue(rc == 0); + assertTrue(jdepsRunner.outputContains("java.base,m1")); + } + + /* + * Detect multiple versions of p.internal.P class + */ + @Test + public void classInMultiVersions() { + JdepsRunner jdepsRunner = new JdepsRunner("--print-module-deps", "--multi-release", "13", + "--module-path", "m1.jar", "m3.jar"); + int rc = jdepsRunner.run(true); + assertTrue(rc != 0); + assertTrue(jdepsRunner.outputContains("class p.internal.P already associated with version")); + } + + private static void jar(String... options) { + int rc = JAR_TOOL.run(System.out, System.err, options); + assertTrue(rc == 0); + } +} diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m1/module-info.java openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m1/module-info.java --- openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m1/module-info.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m1/module-info.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module m1 { + requires java.management; + exports p; +} diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m1/p/internal/P.java openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m1/p/internal/P.java --- openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m1/p/internal/P.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m1/p/internal/P.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 p.internal; + +import java.lang.management.*; + +class P { + private static RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean(); +} diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m1/p/Test.java openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m1/p/Test.java --- openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m1/p/Test.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m1/p/Test.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 p; + +public class Test { +} diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m2/module-info.java openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m2/module-info.java --- openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m2/module-info.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m2/module-info.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module m2 { + requires m1; + requires java.logging; +} diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m2/p/internal/P.java openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m2/p/internal/P.java --- openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m2/p/internal/P.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m2/p/internal/P.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 p.internal; + +import java.util.logging.Logger; + +public class P { + private static final Logger LOGGER = Logger.getLogger("p"); +} diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m2/q/Q.java openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m2/q/Q.java --- openjdk-17-17.0.3+7/test/langtools/tools/jdeps/multiVersion/src/m2/q/Q.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/jdeps/multiVersion/src/m2/q/Q.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 q; + +public class Q { + static p.Test t = new p.Test(); + + public Q() { + Object o = new p.internal.P(); + } +} diff -Nru openjdk-17-17.0.3+7/test/langtools/tools/lib/toolbox/ToolBox.java openjdk-17-17.0.4+8/test/langtools/tools/lib/toolbox/ToolBox.java --- openjdk-17-17.0.3+7/test/langtools/tools/lib/toolbox/ToolBox.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/langtools/tools/lib/toolbox/ToolBox.java 2022-07-14 08:05:38.000000000 +0000 @@ -34,10 +34,10 @@ import java.io.Writer; import java.net.URI; import java.nio.charset.Charset; -import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; @@ -48,6 +48,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Deque; +import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -65,8 +66,6 @@ import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; -import javax.tools.JavaFileManager.Location; import javax.tools.SimpleJavaFileObject; import javax.tools.ToolProvider; @@ -107,11 +106,11 @@ public static final float timeoutFactor; static { String ttf = System.getProperty("test.timeout.factor"); - timeoutFactor = (ttf == null) ? 1.0f : Float.valueOf(ttf); + timeoutFactor = (ttf == null) ? 1.0f : Float.parseFloat(ttf); } /** The current directory. */ - public static final Path currDir = Paths.get("."); + public static final Path currDir = Path.of("."); /** The stream used for logging output. */ public PrintStream out = System.err; @@ -127,6 +126,7 @@ /** * Splits a string around matches of the given regular expression. * If the string is empty, an empty list will be returned. + * * @param text the string to be split * @param sep the delimiting regular expression * @return the strings between the separators @@ -139,6 +139,7 @@ /** * Checks if two lists of strings are equal. + * * @param l1 the first list of strings to be compared * @param l2 the second list of strings to be compared * @throws Error if the lists are not equal @@ -166,6 +167,7 @@ /** * Filters a list of strings according to the given regular expression, * returning the strings that match the regular expression. + * * @param regex the regular expression * @param lines the strings to be filtered * @return the strings matching the regular expression @@ -177,8 +179,9 @@ /** * Filters a list of strings according to the given regular expression, * returning the strings that match the regular expression. + * * @param pattern the regular expression - * @param lines the strings to be filtered + * @param lines the strings to be filtered * @return the strings matching the regular expression */ public List grep(Pattern pattern, List lines) { @@ -188,6 +191,7 @@ /** * Filters a list of strings according to the given regular expression, * returning either the strings that match or the strings that do not match. + * * @param regex the regular expression * @param lines the strings to be filtered * @param match if true, return the lines that match; otherwise if false, return the lines that do not match. @@ -200,9 +204,10 @@ /** * Filters a list of strings according to the given regular expression, * returning either the strings that match or the strings that do not match. + * * @param pattern the regular expression - * @param lines the strings to be filtered - * @param match if true, return the lines that match; otherwise if false, return the lines that do not match. + * @param lines the strings to be filtered + * @param match if true, return the lines that match; otherwise if false, return the lines that do not match. * @return the strings matching(or not matching) the regular expression */ public List grep(Pattern pattern, List lines, boolean match) { @@ -217,12 +222,13 @@ * in that directory. Otherwise, the copy will be placed at the destination, * possibly overwriting any existing file. *

    Similar to the shell "cp" command: {@code cp from to}. + * * @param from the file to be copied - * @param to where to copy the file + * @param to where to copy the file * @throws IOException if any error occurred while copying the file */ public void copyFile(String from, String to) throws IOException { - copyFile(Paths.get(from), Paths.get(to)); + copyFile(Path.of(from), Path.of(to)); } /** @@ -231,8 +237,9 @@ * in that directory. Otherwise, the copy will be placed at the destination, * possibly overwriting any existing file. *

    Similar to the shell "cp" command: {@code cp from to}. + * * @param from the file to be copied - * @param to where to copy the file + * @param to where to copy the file * @throws IOException if an error occurred while copying the file */ public void copyFile(Path from, Path to) throws IOException { @@ -245,10 +252,55 @@ } /** - * Creates one of more directories. + * Copies the contents of a directory to another directory. + *

    Similar to the shell command: {@code rsync fromDir/ toDir/}. + * + * @param fromDir the directory containing the files to be copied + * @param toDir the destination to which to copy the files + */ + public void copyDir(String fromDir, String toDir) { + copyDir(Path.of(fromDir), Path.of(toDir)); + } + + /** + * Copies the contents of a directory to another directory. + * The destination direction should not already exist. + *

    Similar to the shell command: {@code rsync fromDir/ toDir/}. + * + * @param fromDir the directory containing the files to be copied + * @param toDir the destination to which to copy the files + */ + public void copyDir(Path fromDir, Path toDir) { + try { + if (toDir.getParent() != null) { + Files.createDirectories(toDir.getParent()); + } + Files.walkFileTree(fromDir, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path fromSubdir, BasicFileAttributes attrs) + throws IOException { + Files.copy(fromSubdir, toDir.resolve(fromDir.relativize(fromSubdir))); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path fromFile, BasicFileAttributes attrs) + throws IOException { + Files.copy(fromFile, toDir.resolve(fromDir.relativize(fromFile))); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + throw new Error("Could not copy " + fromDir + " to " + toDir + ": " + e, e); + } + } + + /** + * Creates one or more directories. * For each of the series of paths, a directory will be created, * including any necessary parent directories. *

    Similar to the shell command: {@code mkdir -p paths}. + * * @param paths the directories to be created * @throws IOException if an error occurred while creating the directories */ @@ -256,7 +308,7 @@ if (paths.length == 0) throw new IllegalArgumentException("no directories specified"); for (String p : paths) - Files.createDirectories(Paths.get(p)); + Files.createDirectories(Path.of(p)); } /** @@ -264,6 +316,7 @@ * For each of the series of paths, a directory will be created, * including any necessary parent directories. *

    Similar to the shell command: {@code mkdir -p paths}. + * * @param paths the directories to be created * @throws IOException if an error occurred while creating the directories */ @@ -278,6 +331,7 @@ * Deletes one or more files, awaiting confirmation that the files * no longer exist. Any directories to be deleted must be empty. *

    Similar to the shell command: {@code rm files}. + * * @param files the names of the files to be deleted * @throws IOException if an error occurred while deleting the files */ @@ -289,6 +343,7 @@ * Deletes one or more files, awaiting confirmation that the files * no longer exist. Any directories to be deleted must be empty. *

    Similar to the shell command: {@code rm files}. + * * @param paths the paths for the files to be deleted * @throws IOException if an error occurred while deleting the files */ @@ -300,6 +355,7 @@ * Deletes one or more files, awaiting confirmation that the files * no longer exist. Any directories to be deleted must be empty. *

    Similar to the shell command: {@code rm files}. + * * @param paths the paths for the files to be deleted * @throws IOException if an error occurred while deleting the files */ @@ -319,6 +375,7 @@ /** * Deletes all content of a directory (but not the directory itself), * awaiting confirmation that the content has been deleted. + * * @param root the directory to be cleaned * @throws IOException if an error occurs while cleaning the directory */ @@ -326,20 +383,20 @@ if (!Files.isDirectory(root)) { throw new IOException(root + " is not a directory"); } - Files.walkFileTree(root, new SimpleFileVisitor() { + Files.walkFileTree(root, new SimpleFileVisitor<>() { private IOException ioe = null; // for each directory we visit, maintain a list of the files that we try to delete - private Deque> dirFiles = new LinkedList<>(); + private final Deque> dirFiles = new LinkedList<>(); @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes a) throws IOException { + public FileVisitResult visitFile(Path file, BasicFileAttributes a) { ioe = deleteFile(file, ioe); dirFiles.peekFirst().add(file); return FileVisitResult.CONTINUE; } @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes a) throws IOException { + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes a) { if (!dir.equals(root)) { dirFiles.peekFirst().add(dir); } @@ -369,10 +426,11 @@ * It does not wait to confirm deletion, nor does it retry. * If an exception occurs it is either returned or added to the set of * suppressed exceptions for an earlier exception. + * * @param path the path for the file to be deleted - * @param ioe the earlier exception, or null + * @param ioe the earlier exception, or null * @return the earlier exception or an exception that occurred while - * trying to delete the file + * trying to delete the file */ private IOException deleteFile(Path path, IOException ioe) { try { @@ -389,6 +447,7 @@ /** * Wait until it is confirmed that a set of files have been deleted. + * * @param paths the paths for the files to be deleted * @throws IOException if a file has not been deleted */ @@ -401,6 +460,7 @@ /** * Wait until it is confirmed that a file has been deleted. + * * @param path the path for the file to be deleted * @throws IOException if problems occur while deleting the file */ @@ -431,12 +491,13 @@ * to that directory. Otherwise, the file will be moved to the destination, * possibly overwriting any existing file. *

    Similar to the shell "mv" command: {@code mv from to}. + * * @param from the file to be moved - * @param to where to move the file + * @param to where to move the file * @throws IOException if an error occurred while moving the file */ public void moveFile(String from, String to) throws IOException { - moveFile(Paths.get(from), Paths.get(to)); + moveFile(Path.of(from), Path.of(to)); } /** @@ -445,8 +506,9 @@ * to that directory. Otherwise, the file will be moved to the destination, * possibly overwriting any existing file. *

    Similar to the shell "mv" command: {@code mv from to}. + * * @param from the file to be moved - * @param to where to move the file + * @param to where to move the file * @throws IOException if an error occurred while moving the file */ public void moveFile(Path from, Path to) throws IOException { @@ -461,6 +523,7 @@ /** * Reads the lines of a file. * The file is read using the default character encoding. + * * @param path the file to be read * @return the lines of the file * @throws IOException if an error occurred while reading the file @@ -472,6 +535,7 @@ /** * Reads the lines of a file. * The file is read using the default character encoding. + * * @param path the file to be read * @return the lines of the file * @throws IOException if an error occurred while reading the file @@ -482,18 +546,20 @@ /** * Reads the lines of a file using the given encoding. - * @param path the file to be read + * + * @param path the file to be read * @param encoding the encoding to be used to read the file * @return the lines of the file. * @throws IOException if an error occurred while reading the file */ public List readAllLines(String path, String encoding) throws IOException { - return readAllLines(Paths.get(path), encoding); + return readAllLines(Path.of(path), encoding); } /** * Reads the lines of a file using the given encoding. - * @param path the file to be read + * + * @param path the file to be read * @param encoding the encoding to be used to read the file * @return the lines of the file * @throws IOException if an error occurred while reading the file @@ -509,6 +575,7 @@ /** * Find .java files in one or more directories. *

    Similar to the shell "find" command: {@code find paths -name \*.java}. + * * @param paths the directories in which to search for .java files * @return the .java files found * @throws IOException if an error occurred while searching for files @@ -520,18 +587,18 @@ /** * Find files matching the file extension, in one or more directories. *

    Similar to the shell "find" command: {@code find paths -name \*.ext}. + * * @param fileExtension the extension to search for - * @param paths the directories in which to search for files + * @param paths the directories in which to search for files * @return the files matching the file extension * @throws IOException if an error occurred while searching for files */ public Path[] findFiles(String fileExtension, Path... paths) throws IOException { Set files = new TreeSet<>(); // use TreeSet to force a consistent order for (Path p : paths) { - Files.walkFileTree(p, new SimpleFileVisitor() { + Files.walkFileTree(p, new SimpleFileVisitor<>() { @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { if (file.getFileName().toString().endsWith(fileExtension)) { files.add(file); } @@ -539,24 +606,26 @@ } }); } - return files.toArray(new Path[files.size()]); + return files.toArray(new Path[0]); } /** * Writes a file containing the given content. * Any necessary directories for the file will be created. - * @param path where to write the file + * + * @param path where to write the file * @param content the content for the file * @throws IOException if an error occurred while writing the file */ public void writeFile(String path, String content) throws IOException { - writeFile(Paths.get(path), content); + writeFile(Path.of(path), content); } /** * Writes a file containing the given content. * Any necessary directories for the file will be created. - * @param path where to write the file + * + * @param path where to write the file * @param content the content for the file * @throws IOException if an error occurred while writing the file */ @@ -580,7 +649,8 @@ *

    Note: the content is analyzed using regular expressions; * errors can occur if any contents have initial comments that might trip * up the analysis. - * @param dir the base directory + * + * @param dir the base directory * @param contents the contents of the files to be written * @throws IOException if an error occurred while writing any of the files. */ @@ -593,17 +663,19 @@ } /** - * Returns the path for the binary of a JDK tool within {@link testJDK}. + * Returns the path for the binary of a JDK tool within {@link #testJDK}. + * * @param tool the name of the tool * @return the path of the tool */ public Path getJDKTool(String tool) { - return Paths.get(testJDK, "bin", tool); + return Path.of(testJDK, "bin", tool); } /** * Returns a string representing the contents of an {@code Iterable} as a list. - * @param the type parameter of the {@code Iterable} + * + * @param the type parameter of the {@code Iterable} * @param items the iterable * @return the string */ @@ -624,8 +696,9 @@ /** * Creates a in-memory file object for Java source code. + * * @param className the name of the class - * @param source the source text + * @param source the source text */ public JavaSource(String className, String source) { super(URI.create(className), JavaFileObject.Kind.SOURCE); @@ -635,6 +708,7 @@ /** * Creates a in-memory file object for Java source code. * The name of the class will be inferred from the source code. + * * @param source the source text */ public JavaSource(String source) { @@ -645,6 +719,7 @@ /** * Writes the source code to a file in the current directory. + * * @throws IOException if there is a problem writing the file */ public void write() throws IOException { @@ -653,6 +728,7 @@ /** * Writes the source code to a file in a specified directory. + * * @param dir the directory * @throws IOException if there is a problem writing the file */ @@ -669,13 +745,13 @@ return source; } - private static Pattern commentPattern = + private final static Pattern commentPattern = Pattern.compile("(?s)(\\s+//.*?\n|/\\*.*?\\*/)"); - private static Pattern modulePattern = + private final static Pattern modulePattern = Pattern.compile("module\\s+((?:\\w+\\.)*)"); - private static Pattern packagePattern = - Pattern.compile("package\\s+(((?:\\w+\\.)*)(?:\\w+))"); - private static Pattern classPattern = + private final static Pattern packagePattern = + Pattern.compile("package\\s+(((?:\\w+\\.)*)\\w+)"); + private final static Pattern classPattern = Pattern.compile("(?:public\\s+)?(?:class|enum|interface|record)\\s+(\\w+)"); /** @@ -689,7 +765,7 @@ Matcher matcher = commentPattern.matcher(source); int start = 0; while (matcher.find()) { - sb.append(source.substring(start, matcher.start())); + sb.append(source, start, matcher.start()); start = matcher.end(); } sb.append(source.substring(start)); @@ -725,10 +801,11 @@ * Extracts the Java file name from the class declaration. * This method is intended for simple files and uses regular expressions, * so comments matching the pattern can make the method fail. - * @deprecated This is a legacy method for compatibility with ToolBox v1. - * Use {@link JavaSource#getName JavaSource.getName} instead. + * * @param source the source text * @return the Java file name inferred from the source + * @deprecated This is a legacy method for compatibility with ToolBox v1. + * Use {@link JavaSource#getName JavaSource.getName} instead. */ @Deprecated public static String getJavaFileNameFromSource(String source) { @@ -741,11 +818,15 @@ "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" ); - /**Validate if a given name is a valid file name + /** + * Validates if a given name is a valid file name * or path name on known platforms. + * + * @param name the name + * @throws IllegalArgumentException if the name is a reserved name */ public static void validateName(String name) { - for (String part : name.split("\\.|/|\\\\")) { + for (String part : name.split("[./\\\\]")) { if (RESERVED_NAMES.contains(part.toLowerCase(Locale.US))) { throw new IllegalArgumentException("Name: " + name + " is" + "a reserved name on Windows, " + @@ -753,12 +834,8 @@ } } } - /** - * A memory file manager, for saving generated files in memory. - * The file manager delegates to a separate file manager for listing and - * reading input files. - */ - public static class MemoryFileManager extends ForwardingJavaFileManager { + + public static class MemoryFileManager extends ForwardingJavaFileManager { private interface Content { byte[] getBytes(); String getString(); @@ -770,7 +847,7 @@ private final Map> files; /** - * Construct a memory file manager which stores output files in memory, + * Constructs a memory file manager which stores output files in memory, * and delegates to a default file manager for input files. */ public MemoryFileManager() { @@ -778,8 +855,9 @@ } /** - * Construct a memory file manager which stores output files in memory, + * Constructs a memory file manager which stores output files in memory, * and delegates to a specified file manager for input files. + * * @param fileManager the file manager to be used for input files */ public MemoryFileManager(JavaFileManager fileManager) { @@ -799,6 +877,7 @@ /** * Returns the set of names of files that have been written to a given * location. + * * @param location the location * @return the set of file names */ @@ -811,8 +890,9 @@ /** * Returns the content written to a file in a given location, * or null if no such file has been written. + * * @param location the location - * @param name the name of the file + * @param name the name of the file * @return the content as an array of bytes */ public byte[] getFileBytes(Location location, String name) { @@ -823,8 +903,9 @@ /** * Returns the content written to a file in a given location, * or null if no such file has been written. + * * @param location the location - * @param name the name of the file + * @param name the name of the file * @return the content as a string */ public String getFileString(Location location, String name) { @@ -838,10 +919,8 @@ } private void save(Location location, String name, Content content) { - Map filesForLocation = files.get(location); - if (filesForLocation == null) - files.put(location, filesForLocation = new HashMap<>()); - filesForLocation.put(name, content); + files.computeIfAbsent(location, k -> new HashMap<>()) + .put(name, content); } /** @@ -853,7 +932,10 @@ /** * Constructs a memory file object. - * @param name binary name of the class to be stored in this file object + * + * @param location the location in which to save the file object + * @param name binary name of the class to be stored in this file object + * @param kind the kind of file object */ MemoryFileObject(Location location, String name, JavaFileObject.Kind kind) { super(URI.create("mfm:///" + name.replace('.','/') + kind.extension), @@ -890,7 +972,7 @@ @Override public void close() throws IOException { out.close(); - String text = ((StringWriter) out).toString(); + String text = out.toString(); save(location, name, new Content() { @Override public byte[] getBytes() { diff -Nru openjdk-17-17.0.3+7/test/lib/jdk/test/lib/Platform.java openjdk-17-17.0.4+8/test/lib/jdk/test/lib/Platform.java --- openjdk-17-17.0.3+7/test/lib/jdk/test/lib/Platform.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/lib/jdk/test/lib/Platform.java 2022-07-14 08:05:38.000000000 +0000 @@ -79,7 +79,7 @@ } public static boolean isTieredSupported() { - return compiler.contains("Tiered Compilers"); + return (compiler != null) && compiler.contains("Tiered Compilers"); } public static boolean isInt() { diff -Nru openjdk-17-17.0.3+7/test/lib/jdk/test/lib/security/SecurityUtils.java openjdk-17-17.0.4+8/test/lib/jdk/test/lib/security/SecurityUtils.java --- openjdk-17-17.0.3+7/test/lib/jdk/test/lib/security/SecurityUtils.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/lib/jdk/test/lib/security/SecurityUtils.java 2022-07-14 08:05:38.000000000 +0000 @@ -61,11 +61,18 @@ List.of(protocols)); } - private static void removeFromDisabledAlgs(String prop, List algs) { + /** + * Removes constraints that contain the specified constraint from the + * specified security property. For example, List.of("SHA1") will remove + * any constraint containing "SHA1". + */ + public static void removeFromDisabledAlgs(String prop, + List constraints) { String value = Security.getProperty(prop); value = Arrays.stream(value.split(",")) .map(s -> s.trim()) - .filter(s -> !algs.contains(s)) + .filter(s -> constraints.stream() + .allMatch(constraint -> !s.contains(constraint))) .collect(Collectors.joining(",")); Security.setProperty(prop, value); } diff -Nru openjdk-17-17.0.3+7/test/lib/jdk/test/lib/security/XMLUtils.java openjdk-17-17.0.4+8/test/lib/jdk/test/lib/security/XMLUtils.java --- openjdk-17-17.0.3+7/test/lib/jdk/test/lib/security/XMLUtils.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/lib/jdk/test/lib/security/XMLUtils.java 2022-07-14 08:05:38.000000000 +0000 @@ -92,9 +92,11 @@ Asserts.assertTrue(v2.validate(s3.sign(d))); // can read KeyInfo Asserts.assertTrue(v2.secureValidation(false).validate(s3.sign(p.toUri()))); // can read KeyInfo Asserts.assertTrue(v2.secureValidation(false).baseURI(b).validate( - s3.sign(p.getParent().toUri(), p.getFileName().toUri()))); // can read KeyInfo + s3.sign(p.toAbsolutePath().getParent().toUri(), p.getFileName().toUri()))); // can read KeyInfo Asserts.assertTrue(v1.validate(s1.sign("text"))); // plain text Asserts.assertTrue(v1.validate(s1.sign("binary".getBytes()))); // raw data + Asserts.assertTrue(v1.validate(s1.signEnveloping(d, "x", "#x"))); + Asserts.assertTrue(v1.validate(s1.signEnveloping(d, "x", "#xpointer(id('x'))"))); } //////////// CONVERT //////////// @@ -347,14 +349,14 @@ } // Signs a document in enveloping mode - public Document signEnveloping(Document document) throws Exception { + public Document signEnveloping(Document document, String id, String ref) throws Exception { Document newDocument = DocumentBuilderFactory.newInstance() .newDocumentBuilder().newDocument(); FAC.newXMLSignature( - buildSignedInfo(FAC.newReference("#object", dm)), + buildSignedInfo(FAC.newReference(ref, dm)), buildKeyInfo(), List.of(FAC.newXMLObject(List.of(new DOMStructure(document.getDocumentElement())), - "object", null, null)), + id, null, null)), null, null) .sign(new DOMSignContext(privateKey, newDocument)); @@ -474,7 +476,7 @@ // If key is not null, any key from the signature will be ignored public boolean validate(Document document, PublicKey key) throws Exception { - NodeList nodeList = document.getElementsByTagName("Signature"); + NodeList nodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); if (nodeList.getLength() == 1) { Node signatureNode = nodeList.item(0); if (signatureNode != null) { diff -Nru openjdk-17-17.0.3+7/test/lib/jdk/test/whitebox/WhiteBox.java openjdk-17-17.0.4+8/test/lib/jdk/test/whitebox/WhiteBox.java --- openjdk-17-17.0.3+7/test/lib/jdk/test/whitebox/WhiteBox.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/lib/jdk/test/whitebox/WhiteBox.java 2022-07-14 08:05:38.000000000 +0000 @@ -594,6 +594,7 @@ public native boolean areSharedStringsIgnored(); public native boolean isCDSIncluded(); public native boolean isJFRIncluded(); + public native boolean isDTraceIncluded(); public native boolean isJavaHeapArchiveSupported(); public native Object getResolvedReferences(Class c); public native void linkClass(Class c); diff -Nru openjdk-17-17.0.3+7/test/lib/sun/hotspot/WhiteBox.java openjdk-17-17.0.4+8/test/lib/sun/hotspot/WhiteBox.java --- openjdk-17-17.0.3+7/test/lib/sun/hotspot/WhiteBox.java 2022-04-19 19:55:43.000000000 +0000 +++ openjdk-17-17.0.4+8/test/lib/sun/hotspot/WhiteBox.java 2022-07-14 08:05:38.000000000 +0000 @@ -595,6 +595,7 @@ public native boolean areSharedStringsIgnored(); public native boolean isCDSIncluded(); public native boolean isJFRIncluded(); + public native boolean isDTraceIncluded(); public native boolean isJavaHeapArchiveSupported(); public native Object getResolvedReferences(Class c); public native void linkClass(Class c); diff -Nru openjdk-17-17.0.3+7/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java openjdk-17-17.0.4+8/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java --- openjdk-17-17.0.3+7/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java 1970-01-01 00:00:00.000000000 +0000 +++ openjdk-17-17.0.4+8/test/micro/org/openjdk/bench/vm/compiler/InterfacePrivateCalls.java 2022-07-14 08:05:38.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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 org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import java.util.concurrent.TimeUnit; + +@State(Scope.Benchmark) +public class InterfacePrivateCalls { + interface I { + private int bar() { return 0; } + default int foo() { + return bar(); + } + } + + static class C1 implements I {} + static class C2 implements I {} + static class C3 implements I {} + + private I[] objs; + + @Setup(Level.Trial) + public void setupTrial() { + objs = new I[3]; + objs[0] = new C1(); + objs[1] = new C2(); + objs[2] = new C3(); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Fork(value=1, jvmArgsAppend={"-XX:TieredStopAtLevel=1"}) + public void invokePrivateInterfaceMethodC1() { + for (int i = 0; i < objs.length; ++i) { + objs[i].foo(); + } + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Fork(value=1) + public void invokePrivateInterfaceMethodC2() { + for (int i = 0; i < objs.length; ++i) { + objs[i].foo(); + } + } +}